Skip to content

feat: Add OIDC Identity Provider package#54

Open
PieterjanDeClippel wants to merge 11 commits intomasterfrom
feat/identity-provider
Open

feat: Add OIDC Identity Provider package#54
PieterjanDeClippel wants to merge 11 commits intomasterfrom
feat/identity-provider

Conversation

@PieterjanDeClippel
Copy link
Copy Markdown
Member

Summary

  • New MintPlayer.Spark.IdentityProvider NuGet package — self-built OIDC server with Authorization Code + PKCE flow, JWT signing (RSA 2048), consent page, token cleanup, and standard discovery/JWKS endpoints
  • New Demo/SparkId demo app — identity provider managing OIDC Applications and Scopes via the Spark UI, with dev seed data for HR and Fleet clients
  • AddOidcLogin() extension on ISparkBuilder — allows any Spark app to authenticate via an external OIDC provider (wired up in HR and Fleet pointing to SparkId)
  • provideSparkOidcLogin() Angular provider + external login buttons on the ng-spark-auth login component
  • .angular/ added to .gitignore

Key design decisions

  • No OpenIddict dependency — lightweight self-built OIDC using Microsoft.IdentityModel.JsonWebTokens
  • RavenDB document model: OidcApplications, OidcScopes, OidcAuthorizations, OidcTokens collections
  • Library indexes deployed via Registry.AddMiddleware() (same pattern as Messaging package)
  • Inline HTML consent page (StringBuilder) — avoids forcing Razor Pages on consumers
  • Refresh token rotation with single-use auth codes

Test plan

  • Start SparkId (https://localhost:5001), verify OIDC Applications and Scopes appear in sidebar
  • Verify seed data creates 4 default scopes and 2 dev client registrations
  • Test /.well-known/openid-configuration and /.well-known/jwks endpoints
  • Start HR/Fleet, verify "SparkId" external login button appears on login page
  • Test full OIDC flow: HR login → SparkId consent → redirect back with token
  • Verify token refresh and logout flows

🤖 Generated with Claude Code

PieterjanDeClippel and others added 11 commits March 13, 2026 20:19
Self-built OIDC server package with Authorization Code + PKCE flow,
JWT signing, consent page, token cleanup, and discovery endpoints.
Includes SparkId demo app, AddOidcLogin() for HR/Fleet, and
ng-spark-auth external login button support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EntityMapper.ConvertToSerializableDictionary crashed on List<string>
AsDetail properties (e.g. RedirectUris) because String's indexer
property throws TargetParameterCountException on GetValue(). Now skips
dictionary conversion for non-complex types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SparkUsers_ByLogin fanout index for FindByLoginAsync (RavenDB
  rejects multi-field Any() on auto indexes)
- Add /connect/login as a fully MVC login page for the OIDC authorize
  flow (no Angular hybrid — matches the existing /connect/consent pattern)
- Redirect authorize and consent endpoints to /connect/login instead of
  the Angular /login route
- Fix EntityMapper crash on List<string> AsDetail properties (e.g.
  RedirectUris) — skip ConvertToSerializableDictionary for simple types
- Gitignore oidc-signing-key.json (private key material)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e-type array rendering

- Harden OidcApplication model: multiple client secrets with expiration,
  AllowedGrantTypes, AllowedCorsOrigins, client claims, consent settings
- Add scope-to-claim resolution from DB (OidcScope.ClaimTypes) instead of
  hardcoded logic in token generator and userinfo endpoint
- Add client_credentials grant type support
- Add RFC 7662 token introspection endpoint (/connect/introspect)
- Add RFC 7009 token revocation endpoint (/connect/revoke)
- Add dynamic CORS policy for OIDC endpoints based on AllowedCorsOrigins
- Discovery endpoint now loads scopes dynamically from DB
- Fix SparkId appsettings.json to nest RavenDb config under Spark section
- Fix simple-type AsDetail array rendering (string[], List<string>) on
  po-detail and po-form components — render as list/input instead of
  empty table with zero columns
- Update PRD with phases 7-11 roadmap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tables

- Replace raw checkbox with bs-toggle-button on po-detail for boolean fields
- Add [border]="true" to AsDetail tables on po-detail page
- Update @mintplayer/ng-bootstrap to 21.12.8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change seed data ConsentType from "implicit" to "explicit" so users
see the consent screen on first login and when new scopes are requested.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace full-page redirect with popup window for external login flow.
The popup completes the OAuth flow and sends the result back to the
parent window via postMessage, matching the MintPlayer pattern.

Also adds PRD for two-factor authentication and popup login.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: GET /spark/auth/logins and DELETE /spark/auth/logins/{provider}
- Angular: SparkProfileComponent showing user info, linked logins with
  remove, and available providers with popup-based add flow
- Route: /profile added to sparkAuthRoutes (guarded by sparkAuthGuard)
- Auth bar: username now links to profile page
- Translation keys added for all four demo apps (en/fr/nl)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a user with TwoFactorEnabled logs in via external OIDC provider,
the callback now redirects to an inline HTML 2FA form instead of
bypassing 2FA. Also adds MVC 2FA page to the Identity Provider's
login flow (previously blocked with a TODO).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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