feat: deferred OIDC auth for unauthenticated authorize requests#5852
feat: deferred OIDC auth for unauthenticated authorize requests#5852Kalabint wants to merge 3 commits intotraccar:masterfrom
Conversation
…ng state
When /api/oidc/authorize is called without an active session (getUserId()==0),
issuing an authorization code is not possible. Previously the endpoint would
proceed and issue a code with userId=0.
Instead, store the authorization request parameters in OidcSessionManager
under a random token (10-min TTL, single-use) and set an httpOnly cookie
(oidc_pending, scoped to /api/oidc). Redirect the browser to / so the
existing SPA login flow runs normally.
Add GET /api/oidc/authorize/resume: after a successful login, the client
calls this endpoint. If a pending authorization is found for the cookie,
consume it and issue a real code for the now-authenticated user, returning
{"location": "<redirect_uri>?code=...&state=..."} for the client to follow.
Returns 204 if no pending authorization exists (non-OIDC login path).
TOKEN_BYTES constant makes the entropy size explicit. putIfAbsent with retry
loop in storePending() makes the uniqueness requirement explicit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
What is the use case exactly? |
|
This solves the 401 error from Suggestion 1 |
|
How does it work in a standard? |
|
As far as I can tell, the OIDC Standard isn't defining this part, just the following:
Source: https://openid.net/specs/openid-connect-core-1_0.html#Authenticates I tested it with my own Mapping Application and Claude Connector. |
|
Then why do we need |
Replace server-side pending state (ConcurrentHashMap + /authorize/resume endpoint) with a signed ES256 JWT set as an httpOnly, SameSite=Lax, scheme-aware Secure cookie (oidc_auth_state). When /api/oidc/authorize is called without an active session, PKCE parameters are packed into the JWT and the browser is redirected to /?return=/api/oidc/authorize. After login, LoginPage.jsx performs a full-page navigation (window.location.href) to that URL. The authorize endpoint detects the cookie, verifies the JWT, re-validates the client and redirect URI, issues the code, and clears the cookie in the response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No, we don't and its not a good way to do it. It seems I was coding up a custom solution, based on my own OIDC Traccar fixes, which influenced the path forward. Reworked the whole to a stateless JWT Cookie based system (had a look how other IdP work), which can also work on Load balanced traccar system. I hope this is better |
|
This still looks overcomplicated. Why can't we just save values in the current session? |
Traccar rotates the session ID on login, dropping any pre-login session values. EC signing just to round-trip public query params is overkill. Reworked to use the ?return URL to carry OIDC params through the login redirect, removing the need for server-side state entirely. - Remove createAuthRequest() and getAuthRequest() from OidcSessionManager - Remove oidc_auth_state cookie from OidcResource - Build ?return URL with full OIDC param set for post-login redirect Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Reworked to have it work without any cookies, and removed the need for server storage/logic entirely. |
| @QueryParam("code_challenge") String codeChallenge, | ||
| @QueryParam("code_challenge_method") String codeChallengeMethod, | ||
| @QueryParam("nonce") String nonce) { | ||
| @QueryParam("nonce") String nonce) throws GeneralSecurityException, JOSEException, StorageException { |
| throw new WebApplicationException(Response.Status.BAD_REQUEST); | ||
| } | ||
|
|
||
| if (getUserId() == 0) { |
There was a problem hiding this comment.
Can you please update description to explain how this implementation works.
/api/oidc/authorizewithout a session currently callsissueCode(userId=0).Instead: park PKCE params server-side, set an httpOnly cookie, redirect to
/.Custom
/authorize/resumeendpoint issues the real code after the userauthenticates. No spec equivalent — the standard doesn't address deferred
auth for SPAs that intercept the authorize redirect.
Pair with traccar-web PR #1756