headplane icon indicating copy to clipboard operation
headplane copied to clipboard

0.6.1 breaks oidc with rauthy

Open Murgeye opened this issue 2 months ago • 4 comments

Description

We use rauthy (v0.32.5) as an OIDC provider for headplane. Before v0.6.1, this worked fine; however, this version causes the following error after requesting and getting a response from the token_endpoint of rauthy:

headplane  | 2025-10-17T12:42:14.269Z [auth] ERROR: Unknown error: ClientError: invalid response encountered
headplane  |     at e (file:///app/node_modules/.pnpm/[email protected]/node_modules/openid-client/build/index.js:116:12)
headplane  |     at errorHandler (file:///app/node_modules/.pnpm/[email protected]/node_modules/openid-client/build/index.js:139:23)
headplane  |     at Module.authorizationCodeGrant (file:///app/node_modules/.pnpm/[email protected]/node_modules/openid-client/build/index.js:953:9)
headplane  |     at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
headplane  |     at async finishAuthFlow (file:///app/build/server/assets/server-build.js:611:17)
headplane  |     at async loader$14 (file:///app/build/server/assets/server-build.js:715:14)
headplane  |     at async callRouteHandler (file:///app/node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/react-router/dist/development/chunk-IFMMFE4R.mjs:509:16)
headplane  |     at async commonRoute.loader (file:///app/node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/react-router/dist/development/chunk-IFMMFE4R.mjs:658:19)
headplane  |     at async file:///app/node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/react-router/dist/development/chunk-UH6JLGW7.mjs:4327:19
headplane  |     at async callLoaderOrAction (file:///app/node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/react-router/dist/development/chunk-UH6JLGW7.mjs:4379:16) {
headplane  |   code: 'OAUTH_INVALID_RESPONSE',
headplane  |   [cause]: [OperationProcessingError]

I assume this error is from oauth4webapi, but I cannot track it down further, since the actual message is not printed to the log.

To debug, I have also dumped the traffic between headplane and rauthy. The offending token response looks like this:

HTTP/1.1 200 OK
content-length: 2157
x-content-type-options: nosniff
referrer-policy: no-referrer
x-robots-tag: noindex, nofollow
content-type: application/json
strict-transport-security: max-age=31536000;includeSubDomains
x-frame-options: DENY
content-security-policy: frame-ancestors 'none'; object-src 'none';
cache-control: no-store
date: Fri, 17 Oct 2025 12:44:56 GMT

{"access_token":"<base64 removed>","token_type":"Bearer","id_token":"<base64 removed>","expires_in":1800,"refresh_token":"<base64 removed>"}

All of the tokens are valid JWTs according to CyberChef.

Below my (pretty basic) headplane oidc config:

oidc:
  issuer: "<rauthy-url>/auth/v1"
  client_id: "headplane"
  client_secret: "<redacted>"
  disable_api_key_login: false
  token_endpoint_auth_method: "client_secret_post"
  headscale_api_key: "<redacted>"
  redirect_uri: "<headplane-url>/admin/oidc/callback"
  user_storage_file: "/var/lib/headplane/users.json"

Relevant Rauthy client config options are:

client_id: headplane
client_config: ["enabled", "confidential", "Force MFA"]
authentication_flows: ["authorization_code", "refresh_token"]
PKCE: ["S256"]
redirect_URIs: ["<heaplane-url>/admin/*"]
scopes: ["email", "openid", "profile", "groups"]
default_scopes: ["openid"]
token_lifetime: 1800
access_token_algorithm: "EdDSA"
id_token_algorithm: "EdDSA"
auth_code_lifetime: 60

If I can provide anything else to help track this down, let me know.

Headplane Version

v0.6.1

Headscale Version

v0.26

Murgeye avatar Oct 17 '25 13:10 Murgeye

Sam here with Pocket ID, configureOidcAuth returns empty config.

lszymkowiak avatar Oct 18 '25 05:10 lszymkowiak

Sam here with Pocket ID, configureOidcAuth returns empty config.

I think this might be a different issue then - with Rauthy, Headplane fails to parse the token response, not the OIDC configuration.

Murgeye avatar Oct 18 '25 06:10 Murgeye

I had a similar issue w/ Pocket-ID and HP 0.6.1 and the error was somewhat cryptic, but it ended up being an expired Headscale API key, just posting here in case someone else runs into it.

chiefy avatar Oct 31 '25 16:10 chiefy

I'll have to spin this up to test locally, but thanks for raising the issue. There is some lingering issue and I think it might be that the OIDC library we use is too strict or something along those lines.

Definitely a goal for 0.7.0!

tale avatar Nov 03 '25 14:11 tale

Please try v0.6.2-beta.2 and let me know if the issue is resolved. You'll need to set server.base_url and also maybe need to set oidc.use_pkce. See the docs for more information: https://headplane.net/features/sso#configuring-oidc

tale avatar Dec 04 '25 16:12 tale

After changing the config, it still did not work. However, after some debugging (also see pull request #384), I found out that openid-client didn't like EdDSA JWT tokens. After setting the signing algorithm to RS256, SSO works for me. It might be a good idea to document this somewhere. Thanks for setting up the beta!

Murgeye avatar Dec 05 '25 08:12 Murgeye

By the way, RS256 is the only algorithm working right now (at least from the ones available in rauthy: RS{256,384,512}, EdDSA).

Murgeye avatar Dec 05 '25 08:12 Murgeye

What do you mean by setting it to RS256? On the Rauthy side? Headplane only supports RS256 for now when using PKCE.

tale avatar Dec 05 '25 15:12 tale

Yes, I meant setting it on the Rauthy side.

Murgeye avatar Dec 05 '25 15:12 Murgeye

I updated the documentation to reflect that PKCE might be required for some providers and that Headplane only supports RS256. https://headplane.net/features/sso

tale avatar Dec 05 '25 20:12 tale