The source code for this portfolio is available on GitHub.

Code: NGINX

Stefan KudlaStefan Kudla | |
Cover image for Code: NGINX

NGINX can even front auth for your entire app!

load_module /root/debuild/nginx-1.15.5/debian/debuild-module-lua/nginx-1.15.5/debian/nginx-module-lua/usr/lib/nginx/modules/ngx_http_lua_module.so;

events {
  worker_connections 128;
}

http {

  lua_package_path '~/lua/?.lua;;';

  resolver 8.8.8.8;

  lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
  lua_ssl_verify_depth 5;

  # cache for discovery metadata documents
  lua_shared_dict discovery 1m;
  # cache for JWKs
  lua_shared_dict jwks 1m;

  # NB: if you have "lua_code_cache off;", use:
  # set $session_secret xxxxxxxxxxxxxxxxxxx;
  # see: https://github.com/bungle/lua-resty-session#notes-about-turning-lua-code-cache-off

  server {
    listen 80;

    location /nginx {
      default_type text/plain;
      return 200 "the NGINX server is working!";
    }

    location / {

      access_by_lua_block {

          local opts = {
             -- the full redirect URI must be protected by this script
             -- redirect_uri = "https://MY_HOST_NAME/redirect_uri",
             -- redirect_uri = "http://localhost:8097/redirect_uri",
             -- redirect_uri = "/redirect_uri",

             -- up until version 1.6.1 you'd specify
             redirect_uri_path = "/redirect_uri",
             -- and the redirect URI became
             -- ngx.var.scheme.."://"..ngx.var.http_host..opts.redirect_uri_path
             -- unless the scheme was overridden using opts.redirect_uri_scheme or an X-Forwarded-Proto header in the incoming request

             discovery = "https://partnerpoc.oktapreview.com/.well-known/openid-configuration",
             client_id = "0oagfbbn3gHhSxJWL0h7",
             client_secret = "{{my_client_secret}}",
             --authorization_params = { hd="zmartzone.eu" },
             scope = "openid email profile",
             -- Refresh the users id_token after 900 seconds without requiring re-authentication
             --refresh_session_interval = 900,
             --iat_slack = 600,
             --redirect_uri_scheme = "https",
             --logout_path = "/logout",
             --redirect_after_logout_uri = "/",
             -- Where should the user be redirected after logout from the RP. This option overides any end_session_endpoint that the OP may have provided in the discovery response.
             --redirect_after_logout_with_id_token_hint = true,
             -- Whether the redirection after logout should include the id token as an hint (if available). This option is used only if redirect_after_logout_uri is set.
             --post_logout_redirect_uri = "https://www.zmartzone.eu/logoutSuccessful",
             -- Where does the RP requests that the OP redirects the user after logout. If this option is set to a relative URI, it will be relative to the OP's logout endpoint, not the RP's.
             --token_endpoint_auth_method = ["client_secret_basic"|"client_secret_post"],
             token_endpoint_auth_method = "client_secret_post",
             ssl_verify = "no",

             --accept_none_alg = false
             -- if your OpenID Connect Provider doesn't sign its id tokens
             -- (uses the "none" signature algorithm) then set this to true.

             --accept_unsupported_alg = true
             -- if you want to reject tokens signed using an algorithm
             -- not supported by lua-resty-jwt set this to false. If
             -- you leave it unset or set it to true, the token signature will not be
             -- verified when an unsupported algorithm is used.

             --renew_access_token_on_expiry = true
             -- whether this plugin shall try to silently renew the access token once it is expired if a refresh token is available.
             -- if it fails to renew the token, the user will be redirected to the authorization endpoint.
             --access_token_expires_in = 3600
             -- Default lifetime in seconds of the access_token if no expires_in attribute is present in the token endpoint response. 

             --access_token_expires_leeway = 0
             --  Expiration leeway for access_token renewal. If this is set, renewal will happen access_token_expires_leeway seconds before the token expiration. This avoids errors in case the access_token just expires when arriving to the OAuth Resource Server.

             -- force_reauthorize = false
             -- When force_reauthorize is set to true the authorization flow will be executed even if a token has been cached already
             --session_contents = {id_token=true}
             -- Whitelist of session content to enable. This can be used to reduce the session size.
             -- When not set everything will be included in the session.
             -- Available are: 
             -- id_token, enc_id_token, user, access_token (includes refresh token)

             -- You can specify timeouts for connect/send/read as a single number (setting all timeouts) or as a table. Values are in milliseconds
             -- timeout = 1000
             -- timeout = { connect = 500, send = 1000, read = 1000 }

             --use_nonce = false
             -- By default the authorization request includes the
             -- nonce paramter. You can use this option to disable it
             -- which may be necessary when talking to a broken OpenID
             -- Connect provider that ignores the paramter as the
             -- id_token will be rejected otherwise.

             -- Optional : use outgoing proxy to the OpenID Connect provider endpoints with the proxy_opts table : 
             -- this requires lua-resty-http >= 0.12
             -- proxy_opts = {
             --    http_proxy  = "http://<proxy_host>:<proxy_port>/",
             --    https_proxy = "http://<proxy_host>:<proxy_port>/"
             -- }

             -- Optional : add decorator for HTTP request that is
             -- applied when lua-resty-openidc talks to the OpenID Connect
             -- provider directly. Can be used to provide extra HTTP headers
             -- or add other similar behavior.
             -- http_request_decorator = function(req)
             --   local h = req.headers or {}
             --   h[EXTRA_HEADER] = 'my extra header'
             --   req.headers = h
             --   return req
             -- end,

          }

          -- call authenticate for OpenID Connect user authentication
          local res, err = require("resty.openidc").authenticate(opts)

          if err then
            ngx.status = 500
            ngx.say(err)
            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
          end

          -- at this point res is a Lua table with 3 keys:
          --   id_token    : a Lua table with the claims from the id_token (required)
          --   access_token: the access token (optional)
          --   user        : a Lua table with the claims returned from the user info endpoint (optional)

          --if res.id_token.hd ~= "zmartzone.eu" then
          --  ngx.exit(ngx.HTTP_FORBIDDEN)
          --end

          --if res.user.email ~= "hans.zandbelt@zmartzone.eu" then
          --  ngx.exit(ngx.HTTP_FORBIDDEN)
          --end

          -- set headers with user info: this will overwrite any existing headers
          -- but also scrub(!) them in case no value is provided in the token

          ngx.req.set_header("X-USER", res.id_token.sub)
          ngx.req.set_header("X-email", res.id_token.email)
          ngx.req.set_header("X-name", res.id_token.name)
          ngx.req.set_header("X-preferred_username", res.id_token.preferred_username)     
  
          --local h = ngx.req.get_headers()
          --for k, v in pairs(h) do
          ngx.log(ngx.ERR, "Mail of OKTA user "..res.id_token.email)
          ngx.log(ngx.ERR, "name of OKTA user "..res.id_token.name)
          ngx.log(ngx.ERR, "preferred_username of OKTA user "..res.id_token.preferred_username)
          --end
      }

      add_header x-okta-sub $http_x_user;
      add_header x-okta-email $http_x_email;
      add_header x-okta-name $http_x_name;
      add_header x-okta-preferred-username $http_x_preferred_username;

      proxy_pass https://okta-headers.herokuapp.com/;

    }
  }
}