fix(authentik): two flow defects that only a real browser sign-in could reveal - #68
Open
ggfto wants to merge 2 commits into
Open
fix(authentik): two flow defects that only a real browser sign-in could reveal#68ggfto wants to merge 2 commits into
ggfto wants to merge 2 commits into
Conversation
…e links The flow was created with authentication: require_unauthenticated. Authentik 2025.x evaluates that requirement against the session that ASKS for a recovery link — which is the gateway's own API call, authenticated as the token's user — so the endpoint answered 400 "Recovery flow not applicable to user" and no link was ever issued. Adding a teammate would have failed on a provider that looked correctly configured. It worked on 2024.8, which is why the mocked tests and the earlier live run against that version both passed. `none` is safe here rather than merely permissive: the flow's write stage, default-password-change-write, ships with user_creation_mode=never_create, so with no pending user it dead-ends instead of minting an account for whoever opens the URL. The only way in remains the one-time flow_token in the link — verified against the live instance, which now returns 200 with a flow_token link, and rejects the flow for an anonymous visitor. Claude-Session: https://claude.ai/code/session_01VRJxBb5fb9RUe2UW5FS4mK
…ation_flow The provider was created with authorization_flow pointing at default-authentication-flow, whose designation is `authentication`. That field wants a flow whose designation is `authorization` — the consent step that runs once the user is already signed in. Authentik accepts the wrong designation without complaint. The provider reads as correctly configured through the API, discovery and JWKS both answer 200, and every check this script and its tests perform passes. The failure appears only in a real browser: the authorize endpoint denies with "Request has been denied. Flow does not apply to current user", because an authentication flow is moot for a user who has just authenticated. That is why it survived a live run against 2024.8 and a live run against 2025.2: neither completed a browser sign-in, only API calls. It broke the first time a person actually tried to log in. Now prefers default-provider-authorization-implicit-consent, falls back to the explicit-consent flow, then to any authorization-designation flow. Claude-Session: https://claude.ai/code/session_01VRJxBb5fb9RUe2UW5FS4mK
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.
Both were found migrating a live production deployment to Authentik 2025.2.4, and both had survived every check the project makes — including a full live run against a real instance. Neither is reachable from the API surface: the provider reads as correctly configured, discovery and JWKS answer 200, and
bootstrap.shis idempotent. They fail only when a person tries to use them.1. The provider's
authorization_flowhad the wrong designationIt was set to
default-authentication-flow, whose designation isauthentication. That field wants a flow whose designation isauthorization— the consent step that runs once the user is already signed in.Authentik accepts the wrong designation without complaint. The first browser sign-in fails with:
...because an authentication flow is moot for a user who has just authenticated. Now prefers
default-provider-authorization-implicit-consent, falls back to explicit consent, then to any authorization-designation flow. On the instance where this was found, that is exactly what its five other providers already used.2. The recovery flow was created as
require_unauthenticatedAuthentik 2025.x evaluates a flow's authentication requirement against the session that asks for a recovery link — which is the gateway's own API call, authenticated as the token's user. So
POST /core/users/{pk}/recovery/answered400 "Recovery flow not applicable to user"and no link was ever issued, meaning adding a teammate would fail on a provider that looked healthy. This worked on 2024.8, which is why the earlier live run passed.noneis safe here rather than merely permissive: the flow's write stage,default-password-change-write, ships withuser_creation_mode=never_create, so with no pending user it dead-ends instead of minting an account for whoever opens the URL. The only way in stays the one-timeflow_tokenin the link.Verified
Against the live 2025.2.4 instance: the recovery endpoint now returns 200 with a
flow_tokenlink, the provider'sauthorization_flowmatches the instance's other providers, and a real browser sign-in completes and resolves to the expected user.What this says about the earlier testing
The previous round added
AuthentikLiveITprecisely so version drift would be caught by a test rather than a person. It did catch three 2025.x API changes. It could not catch either of these, because both live in the browser-facing half of the flow and every API-level assertion passes. Worth remembering before trusting "verified against a live instance" to mean "works".https://claude.ai/code/session_01VRJxBb5fb9RUe2UW5FS4mK