@judo/auth
v0.1.1
Published
OIDC authentication layer for JUDO UI Runtime
Readme
@judo/auth
OIDC authentication layer for JUDO UI Runtime
Purpose
A lightweight wrapper around react-oidc-context / oidc-client-ts that extracts auth configuration from ECore-based Application models, manages realm-based OIDC session caching, maps OIDC claims to principal data, and provides React components/hooks for gating and actor-switching.
Architecture Layer
Layer 3 (Infrastructure) — consumed by app-shell and optionally by application-level code.
Dependencies
@judo/model-api,@judo/model-loader— model types and registry (dependency + peer)@mui/material ^7— UI components (peer)oidc-client-ts ^3— OIDC protocol client (peer)react-oidc-context ^3— React OIDC integration (peer)react ^19— React (peer)
File Structure
src/
├── index.ts # Barrel re-export
├── config/
│ ├── auth-config.ts # Model → config extraction
│ └── oidc-config.ts # OIDC UserManagerSettings builder
├── provider/
│ ├── auth-config-context.tsx # React context for auth config
│ ├── judo-auth-provider.tsx # Top-level auth provider
│ ├── principal-context.tsx # Backend principal context + provider
│ └── realm-cache.ts # Realm → UserManager cache
├── hooks/
│ ├── use-auth.ts # Main auth hook
│ ├── use-require-auth.ts # Redirect-guard hook
│ └── use-actor-switch.ts # Actor-switching hook
├── components/
│ ├── actor-auth-boundary.tsx # Auth gate component
│ └── actor-switch-dialog.tsx # Confirmation dialog
└── utils/
└── claim-mapping.ts # OIDC claim → principal mappingExports Summary
Configuration
| Export | Kind | Description |
| ---------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
| ClaimMapping | interface | Maps a ClaimType enum to a model attribute name (claimType, attributeName). |
| ActorAuthConfig | interface | Actor-level auth config: actorName, requiresAuth, realm?, clientId?, claims. |
| getAuthConfig(app) | function | Extracts an ActorAuthConfig from an Application model. Returns a no-auth stub when authentication is absent. |
| isSameRealm(a, b) | function | Checks whether two ActorAuthConfigs share the same OIDC realm. |
| OidcConfig | interface | Simplified config requiring only issuerUrl; other fields have defaults. |
| OidcOptions | interface | Full OIDC options: issuerUrl, redirectUri, postLogoutRedirectUri, scope?, responseType?. |
| createOidcOptions(config) | function | Expands an OidcConfig into full OidcOptions by applying defaults (window.location.origin). |
| buildOidcConfig(config, options) | function | Constructs UserManagerSettings. Computes authority as ${issuerUrl}/auth/realms/${realm}. |
| validateOidcOptions(options) | function | Validates all required fields and URL parseability. Throws on failure. |
React Providers
| Export | Kind | Description |
| ------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AuthConfigProvider | component | Provides ActorAuthConfig + OidcOptions via React context. |
| useAuthConfig() | hook | Reads auth config context; throws if outside provider. |
| useAuthConfigOptional() | hook | Reads auth config context; returns null if outside provider. |
| JudoAuthProvider | component | Top-level auth provider. If requiresAuth is false, renders children directly. If true, wraps in OIDC AuthProvider using a cached UserManager per realm. Strips ?code=&state= on OIDC callback. |
| PrincipalProvider | component | Provides backend principal state with auto-fetch, refresh (refreshPrincipal), and local override (setPrincipal). Place inside auth boundary + API provider. |
| usePrincipal() | hook | Reads backend principal context; throws if outside PrincipalProvider. |
| usePrincipalOptional() | hook | Reads backend principal context; returns null if outside provider. |
Realm Cache
| Export | Kind | Description |
| ----------------------------------------- | -------- | ----------------------------------------------------------------------------- |
| getOrCreateUserManager(realm, settings) | function | Returns (or creates & caches) a UserManager instance keyed by realm string. |
| clearRealmCache(realm) | function | Removes a specific realm from the cache. |
| clearAllRealmCache() | function | Clears the entire realm cache (test utility). |
| hasRealmInCache(realm) | function | Checks if a realm has a cached UserManager. |
| getCachedRealmCount() | function | Returns number of cached realms. |
React Hooks
| Export | Kind | Description |
| ------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| useAuth() | hook | Main auth hook. Returns unified JudoAuthContext for both authenticated and unauthenticated actors. If no auth required, returns a no-op stub. Otherwise delegates to react-oidc-context and maps claims to principal. |
| useOidcAuthRequired() | hook | Direct access to react-oidc-context's useAuth. For internal use within OIDC provider. |
| useRequireAuth() | hook | Guard hook — triggers signinRedirect via useEffect if auth required but user not authenticated. |
| useActorSwitch(currentApp, getApplication, setActiveApplication) | hook | Manages actor switching. Same-realm → direct switch. Different realms → populates pendingSwitch for confirmation. |
| getSwitchConfigs(currentApp, targetApp) | function | Returns { currentConfig, targetConfig } — both ActorAuthConfigs for a switch dialog. |
React Components
| Export | Kind | Description |
| ------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ActorAuthBoundary | component | Auth gate — renders children immediately for unauthenticated actors, shows loading spinner while OIDC loads, renders children once authenticated. Supports guest access mode (supportGuestAccess + guestComponent props) to show a guest page instead of OIDC redirect. |
| ActorSwitchDialog | component | MUI Dialog confirmation for cross-realm actor switches. Displays current/target actor names and warns when realms differ. |
Utilities
| Export | Kind | Description |
| ----------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| claimTypeToKey(claimType) | function | Maps ClaimType enum value to its OIDC profile claim key string (e.g., EMAIL → 'email'). |
| mapClaimsToPrincipal(profile, mappings) | function | Builds a principal data record from an OIDC profile. Maps 5 standard claims plus custom claim mappings from config. |
Type Exports
| Type | Description |
| ------------------------- | ---------------------------------------------------------------------------------- |
| JudoAuthProviderProps | Props for JudoAuthProvider. |
| AuthConfigContextType | Shape of the auth config context value. |
| AuthConfigProviderProps | Props for AuthConfigProvider. |
| PrincipalContextType | Shape of the principal context value. |
| PrincipalProviderProps | Props for PrincipalProvider. |
| JudoAuthContext | Return type of useAuth(). |
| PrincipalData | OIDC-claim-mapped principal shape (email?, name?, preferredUsername?, etc.). |
| PendingSwitch | Pending actor switch info (targetActor, targetRealm?, requiresConfirmation). |
| UseActorSwitchResult | Return type of useActorSwitch(). |
| ActorAuthBoundaryProps | Props for ActorAuthBoundary. |
| ActorSwitchDialogProps | Props for ActorSwitchDialog. |
Key Patterns
- Conditional OIDC wrapping:
JudoAuthProvideronly mounts the OIDC provider whenrequiresAuthis true - Realm-based session sharing: A module-level
Mapensures actors with the same realm share oneUserManager(and thus one OIDC session) - Model-driven configuration:
getAuthConfigderives everything from theApplicationmodel, keeping auth in sync with the ECore meta-model - Graceful degradation: Every hook handles the "no auth required" case cleanly, returning no-op stubs
- Two-phase actor switching: Same-realm switches happen instantly; cross-realm switches require user confirmation
- Claim mapping pipeline: Standard OIDC claims are always mapped, with model-defined custom claim entries on top
- Optional context access: Dual hooks (
useAuthConfig/useAuthConfigOptional,usePrincipal/usePrincipalOptional) follow the throw-vs-null pattern
