Skip to content

OpenID Connect login plugin (6/7) - #896

Merged
KrzysztofPajak merged 133 commits into
developfrom
feature/oidc-login-plugin
Oct 11, 2026
Merged

KrzysztofPajak merged 133 commits into
developfrom
feature/oidc-login-plugin

Conversation

@KrzysztofPajak

Copy link
Copy Markdown
Member

Type: feature

Issue

A sign-in button for the identity provider next to the other external methods (Google, Facebook). Part 6 of the stack (base: PR 5).

Solution

New plugin Authentication.OpenIdConnect (system name ExternalAuth.OpenIdConnect):

  • ASP.NET Core OpenID Connect handler (new package Microsoft.AspNetCore.Authentication.OpenIdConnect, MIT): authorization code + PKCE, query response mode, user info endpoint, tokens not stored. The Authority, HTTPS metadata and claim names come from OidcResourceServer; the client settings from the appsettings section OidcLogin (ClientId, ClientSecret, Scopes). Not configured: no scheme, a warning in the log, and the button leads to the failure page.
  • Controller: /oidc/login (local returnUrl only), /oidc/callback, /oidc/link (signs the visitor out and asks for one password sign-in), /oidc/link/complete (connects only an account signed in after the link page, with the same e-mail), /oidc/failed (fixed texts, details only in the log).
  • Admin configuration (display order; client id and secret shown read-only / as "set"), resources installed with the plugin.
  • The plugin ships only its own assembly and the handler package; Microsoft.IdentityModel.* comes from the host.

Breaking changes

None (a new plugin, not installed by default).

Testing

  1. dotnet test src/Tests/Grand.Modules.Tests - all pass.
  2. Configure a client as in docs/oidc-resource-server.md 11.3-11.5 (PR 7), install the plugin and activate it in External authentication methods.
  3. Scenarios checked end to end on Keycloak 26.8 and Zitadel v4.19: a new customer gets the registration form without a password; an existing verified customer is signed in and linked; an unverified e-mail or an admin gets "Connect your account", signs in with the password once and next time uses the button only; an admin has /admin after signing in; cancelling at the provider shows the failure page; an external returnUrl goes to the home page; unlinking in My account; an API token of a login-linked user maps to the same customer.

… conditions, scheme always registered

The derived audience and resource_metadata URL come from the store resolved for the request, never from the Host header. Resources with account conditions are refused until those checks exist. With the resource server disabled the Oidc scheme is still registered with no issuer and no keys, so endpoints naming it answer 401. authorization_servers publishes the Authority as configured, an http Authority requires RequireHttpsMetadata=false, garbage tokens log at Information, and the startup skips an uninstalled database.
…e request through a request customer resolver
…back-office accounts; one identity per customer
…, staff and unverified e-mails link by password
…8 and Zitadel v4.19

Web API module flag, provider switch and identity links, Keycloak resource indicators accepted with the
Audience mapper, Zitadel role assertion for user_grants, client_id instead of azp, project-wide aud, and the
target reading user.human.is_email_verified.
…tomer resolution, Deny defaults for the Web API
…s-e2e

# Conflicts:
#	src/Business/Grand.Business.Core/Interfaces/Authentication/IJwtBearerAuthenticationService.cs
#	src/Business/Grand.Business.Core/Interfaces/Customers/IUserApiService.cs
#	src/Core/Grand.Domain/Customers/UserApi.cs
#	src/Web/Grand.Web/App_Data/appsettings.json
…e store's second factor after the provider sign-in, tell an identity linked to another account apart
…ecting fails

An identity whose e-mail the provider did not verify registers with a typed
password and is not connected; it connects later with that password, like an
existing account. Otherwise whoever holds that identity would keep the account
once the owner of the address activates it, even after a password reset.
A failed connection after registration now tells the customer. The random
password of a connected account is 32 random bytes.
Base automatically changed from feature/oidc-login-core to develop October 11, 2026 16:39
if (separator <= 0 ||
!long.TryParse(marker.AsSpan(0, separator), NumberStyles.None, CultureInfo.InvariantCulture, out shown))
return false;
subject = marker[(separator + 1)..];
…code), never replace another signed-in account, clear a stale pending identity on failure, always ask for openid, hide the button without a scheme
Copilot AI balanced review requested due to automatic review settings October 11, 2026 16:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@KrzysztofPajak
KrzysztofPajak merged commit 920ecf0 into develop Oct 11, 2026
6 checks passed
@KrzysztofPajak
KrzysztofPajak deleted the feature/oidc-login-plugin branch October 11, 2026 17:12
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.

2 participants