forgejo: signing in via OIDC always lands on the root page, discarding redirect_to #291

Stängd
öppnade 2026-07-31 20:50:20 +00:00 av supernaut · 0 kommentarer
Ägare

Signing in through Kanidm always lands the user on the Forgejo root page, discarding any redirect_to destination. So a deep link like "sign in to comment on this issue" drops them at the dashboard instead of the issue.

Observed by walking the journey: /user/login?redirect_to=%2Fexplore%2Frepos → Kanidm → signed in → Forgejo root, not /explore/repos.

This is pre-existing, not caused by the login redirect (#290)

Worth stating plainly, because the timing invites the wrong conclusion.

Forgejo's own login-page button links to the OIDC start route with no redirect_to:

href="/user/oauth2/Bitborg%20Auth"

So in the old flow the parameter was captured by the login page into a redirect_to cookie, which persisted in the browser; in the new flow the OIDC start route sets the same cookie from the query string that Caddy passes through. Either way a redirect_to cookie exists when the callback runs. The callback ignores it in both cases.

The Caddy redirect passes more information than Forgejo's own button did, so it cannot have made this worse.

What is actually happening

The parameter is accepted and stored. Verified:

GET /user/oauth2/Bitborg%20Auth?redirect_to=%2Fexplore%2Frepos
  → set-cookie: redirect_to=%2Fexplore%2Frepos; Path=/; HttpOnly; Secure; SameSite=Lax

GET /user/oauth2/Bitborg%20Auth          (control)
  → no redirect_to cookie

The control shows the cookie genuinely derives from the parameter. But the callback then discards it:

GET /user/oauth2/Bitborg%20Auth/callback?code=…&state=…
  → 303 See Other   @ auth/oauth.go:1009(auth.SignInOAuthCallback)

and the browser ends on /.

A caution recorded for whoever picks this up: the original assessment claimed deep links survived, based on the cookie being set. That was insufficient evidence — "the parameter is accepted" and "the destination is used" are different assertions, and only an actual login distinguishes them. Do not close this issue on header evidence.

Not yet investigated

Whether this is a Forgejo bug worth reporting upstream, or a guard we are tripping. SignInOAuthCallback is in routers/web/auth/oauth.go; reading how it chooses the post-login target would settle it. Candidate explanations, unverified:

  • the callback does not read the redirect_to cookie on the OAuth path at all (only for internal sign-in);
  • it reads it but rejects the value, e.g. a same-site or safety check on the decoded path;
  • it clears the cookie earlier in the flow.

Consequence for the break-glass hatch

#290's /user/login?local=1 bypass is now more valuable than credited when it was added: it is the only way to reach Forgejo's own login page, and it is where any future upstream fix would apply.

Done when

Either the behaviour is fixed so a deep link survives OIDC sign-in, or it is confirmed as upstream behaviour with a link to the upstream issue, so nobody re-investigates from scratch.

Signing in through Kanidm always lands the user on the Forgejo root page, discarding any `redirect_to` destination. So a deep link like "sign in to comment on this issue" drops them at the dashboard instead of the issue. Observed by walking the journey: `/user/login?redirect_to=%2Fexplore%2Frepos` → Kanidm → signed in → **Forgejo root**, not `/explore/repos`. ## This is pre-existing, not caused by the login redirect (#290) Worth stating plainly, because the timing invites the wrong conclusion. Forgejo's own login-page button links to the OIDC start route with **no** `redirect_to`: ```html href="/user/oauth2/Bitborg%20Auth" ``` So in the old flow the parameter was captured by the login page into a `redirect_to` cookie, which persisted in the browser; in the new flow the OIDC start route sets the same cookie from the query string that Caddy passes through. Either way a `redirect_to` cookie exists when the callback runs. The callback ignores it in both cases. The Caddy redirect passes *more* information than Forgejo's own button did, so it cannot have made this worse. ## What is actually happening The parameter is accepted and stored. Verified: ``` GET /user/oauth2/Bitborg%20Auth?redirect_to=%2Fexplore%2Frepos → set-cookie: redirect_to=%2Fexplore%2Frepos; Path=/; HttpOnly; Secure; SameSite=Lax GET /user/oauth2/Bitborg%20Auth (control) → no redirect_to cookie ``` The control shows the cookie genuinely derives from the parameter. But the callback then discards it: ``` GET /user/oauth2/Bitborg%20Auth/callback?code=…&state=… → 303 See Other @ auth/oauth.go:1009(auth.SignInOAuthCallback) ``` and the browser ends on `/`. **A caution recorded for whoever picks this up:** the original assessment claimed deep links survived, based on the cookie being set. That was insufficient evidence — "the parameter is accepted" and "the destination is used" are different assertions, and only an actual login distinguishes them. Do not close this issue on header evidence. ## Not yet investigated Whether this is a Forgejo bug worth reporting upstream, or a guard we are tripping. `SignInOAuthCallback` is in `routers/web/auth/oauth.go`; reading how it chooses the post-login target would settle it. Candidate explanations, unverified: - the callback does not read the `redirect_to` cookie on the OAuth path at all (only for internal sign-in); - it reads it but rejects the value, e.g. a same-site or safety check on the decoded path; - it clears the cookie earlier in the flow. ## Consequence for the break-glass hatch `#290`'s `/user/login?local=1` bypass is now more valuable than credited when it was added: it is the only way to reach Forgejo's own login page, and it is where any future upstream fix would apply. ## Done when Either the behaviour is fixed so a deep link survives OIDC sign-in, or it is confirmed as upstream behaviour with a link to the upstream issue, so nobody re-investigates from scratch.
Logga in för att delta i denna konversation.
Ingen milstolpe
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra#291
Ingen beskrivning angiven.