Forward authentication
For services that don't support OpenID Connect, your reverse proxy asks Unlatch about every request and lets it through only for signed-in users who may use the service. How it works is described in the architecture.
- In administration, add an application of the kind Forward auth with the host of the service,
such as
photos.example.com, and choose who may use it. - List the address of your proxy in
UNLATCH_TRUSTED_PROXIES; Unlatch answers forward-auth requests only from there. - Configure the proxy as below. Two things are needed for each protected host: requests to
/_unlatch/go to Unlatch, and every other request is checked first.
The service receives the user in Remote-User, Remote-Name, Remote-Email and Remote-Groups
(group names separated by commas). The configurations below replace whatever the client sent in
these headers; a service must not be reachable around the proxy, or anyone could send them.
In the examples Unlatch runs at https://login.example.com, reachable from the proxy as
unlatch:8080, and the service as photos:2342.
Caddy
photos.example.com {
handle /_unlatch/* {
reverse_proxy unlatch:8080
}
handle {
forward_auth unlatch:8080 {
uri /forward-auth
copy_headers Remote-User Remote-Name Remote-Email Remote-Groups
}
reverse_proxy photos:2342
}
}
Traefik
http:
middlewares:
unlatch:
forwardAuth:
address: http://unlatch:8080/forward-auth
authResponseHeaders: [Remote-User, Remote-Name, Remote-Email, Remote-Groups]
routers:
photos:
rule: Host(`photos.example.com`)
middlewares: [unlatch]
service: photos
photos-unlatch:
rule: Host(`photos.example.com`) && PathPrefix(`/_unlatch/`)
service: unlatch
services:
photos:
loadBalancer:
servers: [{ url: http://photos:2342 }]
unlatch:
loadBalancer:
servers: [{ url: http://unlatch:8080 }]
nginx
nginx's auth_request only understands success or 401, so it uses /forward-auth/nginx, which
answers 401 with the sign-in address in Location and a cookie that ties the sign-in to this
browser; nginx has to pass the cookie on.
server {
server_name photos.example.com;
location /_unlatch/ {
proxy_pass http://unlatch:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /_unlatch_check {
internal;
proxy_pass http://unlatch:8080/forward-auth/nginx;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
auth_request /_unlatch_check;
auth_request_set $sign_in $upstream_http_location;
auth_request_set $sign_in_cookie $upstream_http_set_cookie;
add_header Set-Cookie $sign_in_cookie always;
error_page 401 =302 $sign_in;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
auth_request_set $groups $upstream_http_remote_groups;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Groups $groups;
proxy_pass http://photos:2342;
}
}
Signing out
A link to /_unlatch/logout on the protected host ends its session there and continues to sign
out of Unlatch, which asks the user to confirm.