Skip to content

Back OpenID Connect login with provider sessions - #904

Merged
KrzysztofPajak merged 28 commits into
developfrom
feature/oidc-sessions-plugin
Oct 13, 2026
Merged

KrzysztofPajak merged 28 commits into
developfrom
feature/oidc-sessions-plugin

Conversation

@KrzysztofPajak

Copy link
Copy Markdown
Member

Resolves no public issue
Type: feature

Issue

The OpenID Connect login plugin needs to bind GrandNode sessions to provider session identifiers and react to provider logout signals. Without that, back-channel logout, refresh-token-based revalidation, and provider-side session ending cannot reliably affect existing GrandNode authentication cookies.

Solution

Store OIDC session data during callback processing, add refresh-token-based session confirmation, implement the back-channel logout endpoint and logout token validation, bound logout token replay tracking, refresh provider metadata for unknown signing keys, and add focused plugin tests for session data, logout token validation, back-channel logout, token refresh, and callback behavior.

Breaking changes

None expected. The plugin gains a new back-channel logout endpoint and stores additional session metadata for OIDC-backed sign-ins.

Testing

Not run during PR creation.

  1. Run dotnet test src/Tests/Grand.Modules.Tests/Grand.Modules.Tests.csproj --filter OidcBackChannelLogoutEndpointTests.
  2. Configure the identity provider with the plugin back-channel logout endpoint.
  3. Sign in through OpenID Connect, send a valid logout token for the provider session, and confirm the GrandNode session is ended.
  4. Send malformed, replayed, and unknown-key logout tokens and confirm the endpoint rejects them or refreshes metadata as expected.

…d in again

A re-sign-in after a password, e-mail or username change used the two-argument
SignIn, which dropped grand:oidcSession, so the new cookie escaped idle and
maximum lifetime, revalidation and back-channel logout. The two-argument SignIn
now carries the session of the current cookie over when it belongs to the same
customer.
If ending the server-side session threw, SignOutAsync never ran and the customer
stayed signed in. The failure is now logged as a warning with the session id and
both schemes are always signed out.
It dereferenced the missing entity and threw, while MongoDB treats no match as a
no-op. Conditional updates such as ending an OpenID Connect session that has
already ended rely on the MongoDB behavior.
@KrzysztofPajak

Copy link
Copy Markdown
Member Author

Code review finding:\n\nFile and line: src/Plugins/Authentication.OpenIdConnect/EndpointProvider.cs:23 and src/Web/Grand.Web.Common/Middleware/ContextMiddleware.cs:48\n\nRule violated: security/.NET review: an external server-to-server endpoint should avoid unrelated request context side effects; the route comment says no store context, but middleware does not skip it.\n\nImpact: /oidc/backchannel-logout still runs ContextMiddleware, so a provider POST without cookies can initialize store/work context and potentially create guest/customer context work for every logout call. This is unnecessary on a public webhook-style endpoint and can fail or add noise depending on host/store resolution.\n\nSuggested fix: add the back-channel logout route to the same skip mechanism used for OIDC metadata, or add endpoint metadata that ContextMiddleware honors.\n\nReview scope: security, .NET, plugin/module, auth endpoint behavior, and repo code-review checklist. I did not run the test suites.

…ions deleted, access tokens revoked only on a provider refusal
…ects

A 307 or 308 from the token endpoint would have re-posted the refresh token and
the client secret to another address. The named client no longer follows
redirects, and a redirect answer counts as the provider being unavailable.
…en names an unknown signing key

After the provider rotated its signing keys, logout tokens signed with the new
key were refused until the cached metadata expired, and providers do not retry a
400. The validator now flags an unknown signing key (also when the handler
reports it as an expired token without exp); the endpoint then requests a
metadata refresh, waits briefly for the background refresh of the configuration
manager and validates the token once more.
…he same account end with a session-backed cookie
…ntext, an unconfigured sign-in revokes no access tokens
@KrzysztofPajak
KrzysztofPajak force-pushed the feature/oidc-sessions-plugin branch from 27e9613 to 8b0ff4f Compare October 13, 2026 18:30
@KrzysztofPajak

Copy link
Copy Markdown
Member Author

Agreed, fixed in 8b0ff4f.

A cookieless call did run WorkContextSetter, which inserts a new guest. The comment in EndpointProvider was wrong about that.

I did not add the plugin's path to the skip list in core. Instead, Grand.Web.Common now has endpoint metadata, NoRequestContextMetadata. ContextMiddleware sets neither store nor work context for an endpoint that carries it, and the back-channel logout route adds it with .WithMetadata(...). ContextMiddlewareTests covers the new branch.

The same commit makes OidcTokenRefresher return NotAsked instead of Refused when the sign-in scheme is not configured. A local misconfiguration therefore no longer revokes the subject's access tokens (see #902).

Base automatically changed from feature/oidc-sessions-core to develop October 13, 2026 18:47
@KrzysztofPajak
KrzysztofPajak merged commit 9f72aae into develop Oct 13, 2026
1 check passed
@KrzysztofPajak
KrzysztofPajak deleted the feature/oidc-sessions-plugin branch October 13, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant