Repository navigation
Add optional single sign-on through OpenID Connect (authentik) - #128
Merged
Merged
Conversation
A "Sign in with authentik" button, configured entirely through OIDC_* settings and off by default. Authorization-code flow with PKCE, state and nonce; the ID token's signature (JWKS, or HS256 with the client secret as authentik uses without a signing key), issuer, audience and expiry are verified. Accounts are matched by verified email on the first sign-in and then bound to the provider's subject, so an email change on either side cannot move a sign-in onto another account. With no match, an open invitation is honoured with its role, the first account on an empty instance becomes the administrator, and OIDC_AUTO_CREATE decides everything else. AUTH_PASSWORD_LOGIN=false makes single sign-on the only way in: the password form, sign-up and password invitations disappear, and only administrators may still sign in with a password, through the unlinked break-glass at /login?local=1. The switch is ignored with a warning while SSO is not fully configured. Signing out of an SSO session also ends the provider session (OIDC_SINGLE_LOGOUT), for which the provider's origin is added to the CSP form-action. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9iRDbBMRtJipppd5fLRtL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optional SSO through any OpenID Connect provider, written and documented for authentik. It is off by default, so an existing installation behaves exactly as before.
Decisions (from the questionnaire)
OIDC_AUTO_CREATE(defaultfalse)AUTH_PASSWORD_LOGIN=false/login?local=1, single logoutHow it works
Flow:
GET /api/auth/oidc/login→ provider →GET /api/auth/oidc/callback. Uses the authorization-code flow with PKCE (S256), state and nonce. The flow cookie is HTTP-only and single-use, and the callback is rate limited.Token verification: the ID token's signature is checked against the JWKS, or with HS256 and the client secret when authentik has no signing key set. Issuer, audience and expiry are checked too. If the ID token has no email, the userinfo endpoint is used, and its
submust match.Matching: on the first sign-in the account is found by verified email (case-insensitive) and then bound to the provider's
sub(new columnUser.oidcSubject). Changing the email on either side cannot move a sign-in onto another account. An account already bound to a different subject is refused (ssoConflict).When no account has the email:
REGISTRATION_MODE=disabled);OIDC_AUTO_CREATEdecides.Accounts created this way get an unusable password hash.
AUTH_PASSWORD_LOGIN=false: the password form, the sign-up page and the password form on invitation links are hidden.loginActionaccepts only admins, and refuses everyone else with the same message as a wrong password. If SSO isn't fully configured, the switch is ignored and a warning is logged at start-up, so a typo can't lock everyone out.Single logout: signing out of an SSO session redirects to the provider's
end_session_endpointwithid_token_hint. The ID token is stored in the new columnSession.oidcIdToken. The provider's origin is added to the CSPform-action.An SSO session skips the password-change gate.
Docs: a new README section "Single sign-on" with authentik setup steps, new rows in the env table, and
.env.example.Migration
20261005120000_oidc_ssoadds the two nullable columns plus a unique index. It only adds; nothing is rewritten.Test plan
npm run lint,npm run typecheck,npm test: 1145 passed. Newsrc/lib/oidc.test.tscovers config, the password switch, PKCE (RFC 7636 test vector), the flow cookie, the provisioning policy and usernames.npm run buildssoNoAccountsub→ssoConflictemail_verified: false→ssoUnverifiedssoInactivessoFailedid_token_hint→/login, with no CSP console errorsNote for authentik
Since email decides which account a sign-in reaches,
OIDC_REQUIRE_VERIFIED_EMAILdefaults totrue. If your authentik email scope mapping reportsemail_verified: false, either change the mapping or set the flag tofalse. Only set it tofalseif users can't edit their own email in authentik (see the README).🤖 Generated with Claude Code
https://claude.ai/code/session_01H9iRDbBMRtJipppd5fLRtL
Generated by Claude Code