iFargle / headscale-webui

A simple Headscale web UI for small-scale deployments.
Other
628 stars 57 forks source link

OIDC `redirect_uri` with invalid scheme #82

Closed vbrandl closed 1 year ago

vbrandl commented 1 year ago

I'm running headscale-webui behind a nginx proxy and have DOMAIN_NAME set to https://headscale.example.com.

Now I want to configure OIDC with authelia (running under auth.example.com) as described. The authorization request that is generated looks like this:

https://auth.example.com/api/oidc/authorization?client_id=&redirect_uri=http%3A%2F%2Fheadscale.example.com%2Fadmin%2Foidc_callback&scope=openid+profile+email&access_type=offline&response_type=code&state=&openid.realm=Headscale-WebUI

Notice how the redirect_uri parameter contains the DOMAIN_NAME but with the http scheme instead of https. In my authelia configuration I only allow the https URI as redirect_uri, So I get a 401 Unauthorized.

Adding the http URI to the list of redirect_uris in authelia gets me to the consent page but after confirming, I get another not authorized response, this time by headscale-webui and the following error in the authelia logs:

Authorization Response for Request with id 'XXX' on client with id 'YYY' could not be created: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix 'localhost', for example: http://myapp.localhost/.

How do I configure headscale-webui to set the correct redirect_uri?

iFargle commented 1 year ago

Interesting. I'm using Authelia and have no problems. Your Authelia yaml config matches the one in SETUP.md, correct? I wonder if it's something to do with headers and your nginx proxy?

Can you enable debug logging in headscale-webui and post the output of the first 10 seconds or so of running? It should output the OIDC config its using

vbrandl commented 1 year ago

My authelia config looks like this:

-
        id: headscale-webui
        description: Headscale WebUI
        secret: <snip>
        public: false
        authorization_policy: two_factor
        redirect_uris:
          - https://headscale.example.com/admin/oidc_callback
        scopes:
          - openid
          - profile
          - email

I also configured headscale itself to use the Authelia OIDC provider and this works fine.

Here is the relevant nginx config:

    location /admin {
        set $upstream headscale-webui:5000;
        proxy_pass http://$upstream;
        proxy_http_version 1.1;
        proxy_set_header Host $server_name;
        proxy_buffering off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

        auth_basic "Administrator's Area";
        auth_basic_user_file /etc/nginx/htpasswd.headscale;
    }

Here are the relevant log lines when starting with debug log:

[2023-04-14 12:58:51,486] DEBUG in server: JSON Dumps for OIDC_INFO:  {"issuer": "https://auth.example.com", "jwks_uri": "https://auth.example.com/jwks.json", "authorization_endpoint": "https://auth.example.com/api/oidc/authorization", "token_endpoint": "https://auth.example.com/api/oidc/token", "subject_types_supported": ["public"], "response_types_supported": ["code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"], "response_modes_supported": ["form_post", "query", "fragment"], "scopes_supported": ["offline_access", "openid", "profile", "groups", "email"], "claims_supported": ["amr", "aud", "azp", "client_id", "exp", "iat", "iss", "jti", "rat", "sub", "auth_time", "nonce", "email", "email_verified", "alt_emails", "groups", "preferred_username", "name"], "introspection_endpoint": "https://auth.example.com/api/oidc/introspection", "revocation_endpoint": "https://auth.example.com/api/oidc/revocation", "code_challenge_methods_supported": ["S256"], "require_pushed_authorization_requests": false, "userinfo_endpoint": "https://auth.example.com/api/oidc/userinfo", "id_token_signing_alg_values_supported": ["RS256"], "userinfo_signing_alg_values_supported": ["none", "RS256"], "request_object_signing_alg_values_supported": ["none", "RS256"], "request_uri_parameter_supported": false, "require_request_uri_registration": false, "claims_parameter_supported": false, "frontchannel_logout_supported": false, "frontchannel_logout_session_supported": false, "backchannel_logout_supported": false, "backchannel_logout_session_supported": false}
[2023-04-14 12:58:51,486] DEBUG in server: {"web": {"issuer": "https://auth.example.com", "auth_uri": "https://auth.example.com/api/oidc/authorization", "client_id": "headscale-webui", "client_secret": "<snip>", "redirect_uris": ["https://headscale.example.com/admin/oidc_callback"], "userinfo_uri": "https://auth.example.com/api/oidc/userinfo", "token_uri": "https://auth.example.com/api/oidc/token"}}
willscottuk commented 1 year ago

Having faced this issue myself, you can bodge it it by changing your nginx config.

You'll want to change proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; to proxy_set_header X-Forwarded-Proto https;

I think there's a separate question as to why the DOMAIN_NAME env variable isn't being used in forming the redirect URL - I can confirm your original issue.

vbrandl commented 1 year ago

Thanks. This did the trick for me.