Vouch Proxy
https://github.com/vouch/vouch-proxy
Authentication in nginx with SSO providers (OKTA, Azure AD etc.)
Requirements
- nginx
- nginx auth_request module (included in most nginx packages)
- manual nginx configuration (see below example)
- go
- OKTA application (you need to be OKTA admin)
- Organization domain: domain.company.com
- Client id - Vouch Proxy connects to OKTA with this
- Client secret - Vouch Proxy authenticates to OKTA with this
- Sign-in redirect URIs - OKTA sends response with this
Steps
- Download source code
- Build application bin
- Copy application config
- Create application systemd service
- Run application
- Change nginx configuration
- Reload nginx to apply configuration
Example nginx config
This will set an HTTP header X-Vouch-User
with the value of $auth_resp_x_vouch_user
that your backend server can read in order to know who logged in.
# For Vouch Proxy large cookie support
# large_client_header_buffers 4 16k;
# proxy_buffer_size 16k;
location ~ ^/(auth|login|logout|static) {
proxy_pass http://127.0.0.1:9090;
proxy_set_header Host $http_host;
}
location = /validate {
# forward the /validate request to Vouch Proxy
proxy_pass http://127.0.0.1:9090/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Host $http_host;
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
}
# if validate returns `401 not authorized` then forward the request to the error401 block
error_page 401 = @error401;
location @error401 {
# redirect to Vouch Proxy for login
return 302 $scheme://$http_host/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
}
location / {
# send all requests to the /validate endpoint for authorization
auth_request /validate;
# get Vouch Proxy claims into a local nginx variable
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
auth_request_set $auth_resp_x_vouch_idp_claims_email $upstream_http_x_vouch_idp_claims_email;
auth_request_set $auth_resp_x_vouch_idp_claims_profile $upstream_http_x_vouch_idp_claims_profile;
auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
auth_request_set $auth_resp_x_vouch_idp_idtoken $upstream_http_x_vouch_idp_idtoken;
auth_request_set $auth_resp_x_vouch_idp_accesstoken $upstream_http_x_vouch_idp_accesstoken;
# forward the claim to the proxied server
# for FastCGI you use `fastcgi_param PARAM_NAME $param-value;`
# That you access in PHP with `$_SERVER['PARAM_NAME']`
# For proxy_pass you use `proxy_set_header Header-Name $header_value;`
fastcgi_param REMOTE_VOUCH_USER $auth_resp_x_vouch_user;
fastcgi_param REMOTE_EMAIL $auth_resp_x_vouch_idp_claims_email;
fastcgi_param REMOTE_PROFILE $auth_resp_x_vouch_idp_claims_profile;
fastcgi_param REMOTE_GROUPS $auth_resp_x_vouch_idp_claims_groups;
fastcgi_param REMOTE_IDTOKEN $auth_resp_x_vouch_idp_idtoken;
fastcgi_param REMOTE_ACCESSTOKEN $auth_resp_x_vouch_idp_accesstoken;
# forward authorized requests to your service
include snippets/fastcgi-php.conf;
fastcgi_pass 127.0.0.1:9000;
}
Example vouch-proxy config
vouch:
logLevel: info
listen: 127.0.0.1
port: {{ vouch_proxy_port }}
# domains:
# valid domains that the jwt cookies can be set into
# the callback_urls will be to these domains
# domains:
# - yourdomain.com
# - yourotherdomain.com
# - OR -
# instead of setting specific domains you may prefer to allow all users...
# set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider
# and set vouch.cookie.domain to the domain you wish to protect
allowAllUsers: true
jwt:
# - if `./config/secret` doesn't exist then randomly generate a secret and store it there (service user needs permission)
secret: {{ jwt_secret }}
maxAge: 5
cookie:
name: VouchCookie
# allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com)
secure: false
# vouch.cookie.domain must be set when enabling allowAllUsers
domain: company.com
# Set cookie maxAge to 0 to delete the cookie every time the browser is closed.
maxAge: 0
headers:
jwt: X-Vouch-Token
user: X-Vouch-User
querystring: access_token
redirect: X-Vouch-Requested-URI
idtoken: X-Vouch-IdP-IdToken
accesstoken: X-Vouch-IdP-AccessToken
# claims - a list of claims that will be stored in the JWT and passed down to applications via headers
# By default claims are sent down as headers with a prefix of X-Vouch-IdP-Claims-ClaimKey
claims:
- openid
- groups
- email
- profile
# these will result in headers being passed back to nginx as the headers
# X-Vouch-IdP-Claims-Groups: groupa, groupb, groupc
# X-Vouch-IdP-Claims-Given-Name: Robert
# nginx will populate the variables
# $auth_resp_x_vouch_idp_claims_groups
# $auth_resp_x_vouch_idp_claims_given-name
session:
name: VouchSession
oauth:
provider: oidc
client_id: {{ okta_client_id }}
client_secret: {{ okta_client_secret }}
auth_url: https://sso.provicer.com/oauth2/v1/authorize
token_url: https://sso.provider.com/oauth2/v1/token
user_info_url: https://sso.provider.com/oauth2/v1/userinfo
scopes:
- openid
- groups
- email
- profile
callback_url: {{ callback_url }}
Example SystemD service unit
[Unit]
Description=Vouch Proxy
After=network.target
[Service]
Type=simple
DynamicUser=yes
WorkingDirectory=/opt/vouch_proxy
ExecStart=/opt/vouch_proxy/vouch-proxy
Restart=on-failure
RestartSec=5
StartLimitInterval=60s
StartLimitBurst=3
TimeoutSec=900
[Install]
WantedBy=default.target