@judo/auth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +277 -0
  2. package/README.md +131 -0
  3. package/dist/components/actor-auth-boundary.d.ts +38 -0
  4. package/dist/components/actor-auth-boundary.d.ts.map +1 -0
  5. package/dist/components/actor-switch-dialog.d.ts +38 -0
  6. package/dist/components/actor-switch-dialog.d.ts.map +1 -0
  7. package/dist/components/index.d.ts +3 -0
  8. package/dist/components/index.d.ts.map +1 -0
  9. package/dist/config/auth-config.d.ts +34 -0
  10. package/dist/config/auth-config.d.ts.map +1 -0
  11. package/dist/config/index.d.ts +3 -0
  12. package/dist/config/index.d.ts.map +1 -0
  13. package/dist/config/oidc-config.d.ts +58 -0
  14. package/dist/config/oidc-config.d.ts.map +1 -0
  15. package/dist/hooks/index.d.ts +4 -0
  16. package/dist/hooks/index.d.ts.map +1 -0
  17. package/dist/hooks/use-actor-switch.d.ts +44 -0
  18. package/dist/hooks/use-actor-switch.d.ts.map +1 -0
  19. package/dist/hooks/use-auth.d.ts +54 -0
  20. package/dist/hooks/use-auth.d.ts.map +1 -0
  21. package/dist/hooks/use-require-auth.d.ts +14 -0
  22. package/dist/hooks/use-require-auth.d.ts.map +1 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +315 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/provider/auth-config-context.d.ts +36 -0
  28. package/dist/provider/auth-config-context.d.ts.map +1 -0
  29. package/dist/provider/index.d.ts +5 -0
  30. package/dist/provider/index.d.ts.map +1 -0
  31. package/dist/provider/judo-auth-provider.d.ts +19 -0
  32. package/dist/provider/judo-auth-provider.d.ts.map +1 -0
  33. package/dist/provider/principal-context.d.ts +54 -0
  34. package/dist/provider/principal-context.d.ts.map +1 -0
  35. package/dist/provider/realm-cache.d.ts +37 -0
  36. package/dist/provider/realm-cache.d.ts.map +1 -0
  37. package/dist/utils/claim-mapping.d.ts +18 -0
  38. package/dist/utils/claim-mapping.d.ts.map +1 -0
  39. package/dist/utils/index.d.ts +2 -0
  40. package/dist/utils/index.d.ts.map +1 -0
  41. package/package.json +62 -0
@@ -0,0 +1,44 @@
1
+ import { Application } from '@judo/model-api';
2
+ import { ActorAuthConfig } from '../config';
3
+ /**
4
+ * Pending actor switch information.
5
+ */
6
+ export interface PendingSwitch {
7
+ targetActor: string;
8
+ targetRealm?: string;
9
+ requiresConfirmation: boolean;
10
+ }
11
+ /**
12
+ * Result from useActorSwitch hook.
13
+ */
14
+ export interface UseActorSwitchResult {
15
+ /** Initiate switch to another actor */
16
+ switchActor: (actorName: string) => void;
17
+ /** Pending switch awaiting confirmation (null if none) */
18
+ pendingSwitch: PendingSwitch | null;
19
+ /** Confirm the pending switch */
20
+ confirmSwitch: () => Promise<void>;
21
+ /** Cancel the pending switch */
22
+ cancelSwitch: () => void;
23
+ }
24
+ /**
25
+ * Hook for managing actor switching with realm-aware confirmation.
26
+ *
27
+ * @param currentApp - Current active application
28
+ * @param getApplication - Function to get application by actor name
29
+ * @param setActiveApplication - Function to set active application
30
+ * @returns UseActorSwitchResult
31
+ */
32
+ export declare function useActorSwitch(currentApp: Application, getApplication: (actorName: string) => Application, setActiveApplication: (actorName: string) => void): UseActorSwitchResult;
33
+ /**
34
+ * Get current and target actor configs for switch dialog.
35
+ *
36
+ * @param currentApp - Current application
37
+ * @param targetApp - Target application
38
+ * @returns Object with both configs
39
+ */
40
+ export declare function getSwitchConfigs(currentApp: Application, targetApp: Application): {
41
+ currentConfig: ActorAuthConfig;
42
+ targetConfig: ActorAuthConfig;
43
+ };
44
+ //# sourceMappingURL=use-actor-switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-actor-switch.d.ts","sourceRoot":"","sources":["../../src/hooks/use-actor-switch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,KAAK,eAAe,EAA8B,MAAM,WAAW,CAAC;AAG7E;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,uCAAuC;IACvC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,0DAA0D;IAC1D,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,iCAAiC;IACjC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,gCAAgC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC7B,UAAU,EAAE,WAAW,EACvB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,EAClD,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAC/C,oBAAoB,CAqDtB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,UAAU,EAAE,WAAW,EACvB,SAAS,EAAE,WAAW,GACpB;IAAE,aAAa,EAAE,eAAe,CAAC;IAAC,YAAY,EAAE,eAAe,CAAA;CAAE,CAKnE"}
@@ -0,0 +1,54 @@
1
+ import { AuthContextProps } from 'react-oidc-context';
2
+ /**
3
+ * Principal data derived from OIDC claims.
4
+ */
5
+ export interface PrincipalData {
6
+ email?: string;
7
+ name?: string;
8
+ preferredUsername?: string;
9
+ givenName?: string;
10
+ familyName?: string;
11
+ [key: string]: unknown;
12
+ }
13
+ /**
14
+ * Extended auth context with JUDO-specific additions.
15
+ */
16
+ export interface JudoAuthContext {
17
+ /** Whether authentication is required for this actor */
18
+ requiresAuth: boolean;
19
+ /** Current actor name */
20
+ actorName: string;
21
+ /** Mapped principal data from claims */
22
+ principal: PrincipalData | null;
23
+ /** Whether user is authenticated */
24
+ isAuthenticated: boolean;
25
+ /** Whether auth state is loading */
26
+ isLoading: boolean;
27
+ /** The active OIDC navigator (e.g., 'signinRedirect') or undefined when idle */
28
+ activeNavigator: string | undefined;
29
+ /** The underlying OIDC user object */
30
+ user: AuthContextProps["user"] | null;
31
+ /** Trigger sign-in redirect */
32
+ signinRedirect: () => Promise<void>;
33
+ /** Trigger sign-out redirect */
34
+ signoutRedirect: () => Promise<void>;
35
+ /** Sign out silently */
36
+ signoutSilent: () => Promise<void>;
37
+ /** Remove user from session */
38
+ removeUser: () => Promise<void>;
39
+ /** OIDC error if any */
40
+ error: Error | undefined;
41
+ }
42
+ /**
43
+ * Extended auth hook with principal mapping.
44
+ * Re-exports react-oidc-context with added JUDO functionality.
45
+ *
46
+ * @returns JudoAuthContext
47
+ */
48
+ export declare function useAuth(): JudoAuthContext;
49
+ /**
50
+ * Internal hook that must be called within OIDC provider.
51
+ * Used by components that know auth is required.
52
+ */
53
+ export declare function useOidcAuthRequired(): AuthContextProps;
54
+ //# sourceMappingURL=use-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-auth.d.ts","sourceRoot":"","sources":["../../src/hooks/use-auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAA0B,MAAM,oBAAoB,CAAC;AAInF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,wDAAwD;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IACzB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,sCAAsC;IACtC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACtC,+BAA+B;IAC/B,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,gCAAgC;IAChC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,wBAAwB;IACxB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,wBAAwB;IACxB,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;CACzB;AAuBD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,eAAe,CAyCzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Guard hook that redirects to login if auth required but not authenticated.
3
+ * Should be used in route/page guards.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * function ProtectedPage() {
8
+ * useRequireAuth();
9
+ * return <PageContent />;
10
+ * }
11
+ * ```
12
+ */
13
+ export declare function useRequireAuth(): void;
14
+ //# sourceMappingURL=use-require-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-require-auth.d.ts","sourceRoot":"","sources":["../../src/hooks/use-require-auth.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAQrC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @judo/auth
3
+ *
4
+ * Lightweight OIDC authentication layer for JUDO UI Runtime.
5
+ * Wraps react-oidc-context with minimal overhead.
6
+ */
7
+ export { getAuthConfig, isSameRealm, buildOidcConfig, createOidcOptions, validateOidcOptions, type ActorAuthConfig, type ClaimMapping, type OidcConfig, type OidcOptions, } from './config';
8
+ export { JudoAuthProvider, AuthConfigProvider, useAuthConfig, useAuthConfigOptional, PrincipalProvider, usePrincipal, usePrincipalOptional, getOrCreateUserManager, clearRealmCache, clearAllRealmCache, hasRealmInCache, getCachedRealmCount, type JudoAuthProviderProps, type AuthConfigContextType, type AuthConfigProviderProps, type PrincipalContextType, type PrincipalProviderProps, } from './provider';
9
+ export { useAuth, useOidcAuthRequired, useRequireAuth, useActorSwitch, getSwitchConfigs, type JudoAuthContext, type PrincipalData, type PendingSwitch, type UseActorSwitchResult, } from './hooks';
10
+ export { ActorAuthBoundary, ActorSwitchDialog, type ActorAuthBoundaryProps, type ActorSwitchDialogProps, } from './components';
11
+ export { claimTypeToKey, mapClaimsToPrincipal } from './utils';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACN,aAAa,EACb,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,GAChB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACN,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC3B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACN,OAAO,EACP,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,oBAAoB,GACzB,MAAM,SAAS,CAAC;AAGjB,OAAO,EACN,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC3B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,315 @@
1
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
2
+ import { AuthProvider, hasAuthParams, useAuth as useAuth$1 } from "react-oidc-context";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { UserManager } from "oidc-client-ts";
5
+ import { ClaimType } from "@judo/model-api";
6
+ import { Box, Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from "@mui/material";
7
+ function getAuthConfig(d) {
8
+ return d.authentication ? {
9
+ actorName: d.name,
10
+ requiresAuth: !0,
11
+ realm: d.authentication.realm,
12
+ clientId: `${d.modelName}-${d.name}`,
13
+ claims: d.authentication.claims.map((d) => ({
14
+ claimType: d.type,
15
+ attributeName: d.attributeType.name
16
+ }))
17
+ } : {
18
+ actorName: d.name,
19
+ requiresAuth: !1,
20
+ claims: []
21
+ };
22
+ }
23
+ function isSameRealm(d, B) {
24
+ return !d.requiresAuth && !B.requiresAuth ? !0 : d.requiresAuth === B.requiresAuth ? d.realm === B.realm : !1;
25
+ }
26
+ function createOidcOptions(d) {
27
+ let B = typeof window < "u" ? window.location.origin : "http://localhost:3000";
28
+ return {
29
+ issuerUrl: d.issuerUrl,
30
+ redirectUri: d.redirectUri ?? B,
31
+ postLogoutRedirectUri: d.postLogoutRedirectUri ?? B,
32
+ scope: d.scope
33
+ };
34
+ }
35
+ function buildOidcConfig(d, B) {
36
+ if (!d.requiresAuth) throw Error("Cannot build OIDC config for unauthenticated actor");
37
+ if (!d.realm) throw Error("Realm is required for authenticated actor");
38
+ if (!d.clientId) throw Error("Client ID is required for authenticated actor (derived from Application.name)");
39
+ return {
40
+ authority: `${B.issuerUrl}/auth/realms/${d.realm}`,
41
+ client_id: d.clientId,
42
+ redirect_uri: B.redirectUri,
43
+ post_logout_redirect_uri: B.postLogoutRedirectUri,
44
+ scope: B.scope || "openid profile email",
45
+ response_type: B.responseType || "code",
46
+ automaticSilentRenew: !0,
47
+ loadUserInfo: !0
48
+ };
49
+ }
50
+ function validateOidcOptions(d) {
51
+ if (!d.issuerUrl) throw Error("issuerUrl is required");
52
+ if (!d.redirectUri) throw Error("redirectUri is required");
53
+ if (!d.postLogoutRedirectUri) throw Error("postLogoutRedirectUri is required");
54
+ if (!URL.canParse(d.issuerUrl)) throw Error("issuerUrl must be a valid URL");
55
+ if (!URL.canParse(d.redirectUri)) throw Error("redirectUri must be a valid URL");
56
+ if (!URL.canParse(d.postLogoutRedirectUri)) throw Error("postLogoutRedirectUri must be a valid URL");
57
+ }
58
+ var AuthConfigContext = createContext(null);
59
+ function useAuthConfig() {
60
+ let d = useContext(AuthConfigContext);
61
+ if (!d) throw Error("useAuthConfig must be used within AuthConfigProvider");
62
+ return d;
63
+ }
64
+ function useAuthConfigOptional() {
65
+ return useContext(AuthConfigContext);
66
+ }
67
+ function AuthConfigProvider({ config: d, oidcOptions: B, children: V }) {
68
+ return /* @__PURE__ */ jsx(AuthConfigContext.Provider, {
69
+ value: {
70
+ config: d,
71
+ oidcOptions: B
72
+ },
73
+ children: V
74
+ });
75
+ }
76
+ var realmProviderCache = /* @__PURE__ */ new Map();
77
+ function getOrCreateUserManager(d, B) {
78
+ return realmProviderCache.has(d) || realmProviderCache.set(d, new UserManager(B)), realmProviderCache.get(d);
79
+ }
80
+ function clearRealmCache(d) {
81
+ realmProviderCache.delete(d);
82
+ }
83
+ function clearAllRealmCache() {
84
+ realmProviderCache.clear();
85
+ }
86
+ function hasRealmInCache(d) {
87
+ return realmProviderCache.has(d);
88
+ }
89
+ function getCachedRealmCount() {
90
+ return realmProviderCache.size;
91
+ }
92
+ function JudoAuthProvider({ config: d, oidcOptions: V, children: H }) {
93
+ let W = useCallback(() => {
94
+ window.history.replaceState({}, document.title, window.location.pathname);
95
+ }, []);
96
+ return /* @__PURE__ */ jsx(AuthConfigProvider, {
97
+ config: d,
98
+ oidcOptions: V,
99
+ children: useMemo(() => {
100
+ if (!d.requiresAuth) return /* @__PURE__ */ jsx(Fragment, { children: H });
101
+ let B = buildOidcConfig(d, V);
102
+ return /* @__PURE__ */ jsx(AuthProvider, {
103
+ userManager: getOrCreateUserManager(d.realm, B),
104
+ onSigninCallback: W,
105
+ children: H
106
+ });
107
+ }, [
108
+ d,
109
+ V,
110
+ H,
111
+ W
112
+ ])
113
+ });
114
+ }
115
+ var PrincipalContext = createContext(null);
116
+ function usePrincipal() {
117
+ let d = useContext(PrincipalContext);
118
+ if (!d) throw Error("usePrincipal must be used within a PrincipalProvider");
119
+ return d;
120
+ }
121
+ function usePrincipalOptional() {
122
+ return useContext(PrincipalContext);
123
+ }
124
+ function PrincipalProvider({ fetchPrincipal: d, children: V }) {
125
+ let [K, q] = useState(null), [J, Y] = useState(!1), X = useRef(d);
126
+ X.current = d;
127
+ let Z = useCallback(async () => {
128
+ let d = X.current;
129
+ if (d) {
130
+ Y(!0);
131
+ try {
132
+ q(await d());
133
+ } catch {} finally {
134
+ Y(!1);
135
+ }
136
+ }
137
+ }, []);
138
+ useEffect(() => {
139
+ Z();
140
+ }, [Z]);
141
+ let Q = useCallback((d) => {
142
+ q(d);
143
+ }, []), $ = useMemo(() => ({
144
+ principal: K,
145
+ isLoading: J,
146
+ refreshPrincipal: Z,
147
+ setPrincipal: Q
148
+ }), [
149
+ K,
150
+ J,
151
+ Z,
152
+ Q
153
+ ]);
154
+ return /* @__PURE__ */ jsx(PrincipalContext.Provider, {
155
+ value: $,
156
+ children: V
157
+ });
158
+ }
159
+ function claimTypeToKey(d) {
160
+ return {
161
+ [ClaimType.EMAIL]: "email",
162
+ [ClaimType.USERNAME]: "preferred_username",
163
+ [ClaimType.UNDEFINED]: ""
164
+ }[d] || "";
165
+ }
166
+ function mapClaimsToPrincipal(d, B) {
167
+ if (!d) return {};
168
+ let V = {};
169
+ d.email !== void 0 && (V.email = d.email), d.name !== void 0 && (V.name = d.name), d.preferred_username !== void 0 && (V.preferredUsername = d.preferred_username), d.given_name !== void 0 && (V.givenName = d.given_name), d.family_name !== void 0 && (V.familyName = d.family_name);
170
+ for (let H of B) {
171
+ let B = claimTypeToKey(H.claimType);
172
+ B && d[B] !== void 0 && (V[H.attributeName] = d[B]);
173
+ }
174
+ return V;
175
+ }
176
+ function createUnauthenticatedContext(d) {
177
+ let B = async () => {};
178
+ return {
179
+ requiresAuth: !1,
180
+ actorName: d,
181
+ principal: null,
182
+ isAuthenticated: !1,
183
+ isLoading: !1,
184
+ activeNavigator: void 0,
185
+ user: null,
186
+ signinRedirect: B,
187
+ signoutRedirect: B,
188
+ signoutSilent: B,
189
+ removeUser: B,
190
+ error: void 0
191
+ };
192
+ }
193
+ function useAuth() {
194
+ let d = useAuthConfigOptional();
195
+ if (!d) return createUnauthenticatedContext("unknown");
196
+ let { config: B } = d;
197
+ if (!B.requiresAuth) return createUnauthenticatedContext(B.actorName);
198
+ let V = useAuth$1(), H = useMemo(() => V.user ? mapClaimsToPrincipal(V.user.profile, B.claims) : null, [V.user, B.claims]);
199
+ return {
200
+ requiresAuth: B.requiresAuth,
201
+ actorName: B.actorName,
202
+ principal: H,
203
+ isAuthenticated: V.isAuthenticated,
204
+ isLoading: V.isLoading,
205
+ activeNavigator: V.activeNavigator,
206
+ user: V.user,
207
+ signinRedirect: () => V.signinRedirect(),
208
+ signoutRedirect: () => V.signoutRedirect(),
209
+ signoutSilent: () => V.signoutSilent(),
210
+ removeUser: () => V.removeUser(),
211
+ error: V.error
212
+ };
213
+ }
214
+ function useOidcAuthRequired() {
215
+ return useAuth$1();
216
+ }
217
+ function useRequireAuth() {
218
+ let { requiresAuth: d, isAuthenticated: B, isLoading: V, signinRedirect: U } = useAuth();
219
+ useEffect(() => {
220
+ d && !V && !B && U();
221
+ }, [
222
+ d,
223
+ V,
224
+ B,
225
+ U
226
+ ]);
227
+ }
228
+ function useActorSwitch(d, V, H) {
229
+ let [U, W] = useState(null), { signoutRedirect: K, requiresAuth: q } = useAuth(), J = getAuthConfig(d);
230
+ return {
231
+ switchActor: useCallback((d) => {
232
+ let B = getAuthConfig(V(d));
233
+ J.requiresAuth && !isSameRealm(J, B) ? W({
234
+ targetActor: d,
235
+ targetRealm: B.realm,
236
+ requiresConfirmation: !0
237
+ }) : H(d);
238
+ }, [
239
+ J,
240
+ V,
241
+ H
242
+ ]),
243
+ pendingSwitch: U,
244
+ confirmSwitch: useCallback(async () => {
245
+ U && (q && await K(), H(U.targetActor), W(null));
246
+ }, [
247
+ U,
248
+ q,
249
+ K,
250
+ H
251
+ ]),
252
+ cancelSwitch: useCallback(() => {
253
+ W(null);
254
+ }, [])
255
+ };
256
+ }
257
+ function getSwitchConfigs(d, B) {
258
+ return {
259
+ currentConfig: getAuthConfig(d),
260
+ targetConfig: getAuthConfig(B)
261
+ };
262
+ }
263
+ function DefaultLoading() {
264
+ return /* @__PURE__ */ jsx(Box, {
265
+ display: "flex",
266
+ justifyContent: "center",
267
+ alignItems: "center",
268
+ minHeight: "100vh",
269
+ children: /* @__PURE__ */ jsx(CircularProgress, {})
270
+ });
271
+ }
272
+ function ActorAuthBoundary({ children: d, loadingComponent: B, supportGuestAccess: V, guestComponent: U }) {
273
+ let { requiresAuth: W, isAuthenticated: G, isLoading: K, activeNavigator: J, signinRedirect: X } = useAuth(), Z = !!(V && U);
274
+ return useEffect(() => {
275
+ Z || !W || hasAuthParams() || K || J || G || X();
276
+ }, [
277
+ Z,
278
+ W,
279
+ K,
280
+ J,
281
+ G,
282
+ X
283
+ ]), !W || G ? /* @__PURE__ */ jsx(Fragment, { children: d }) : Z && !K ? /* @__PURE__ */ jsx(Fragment, { children: U }) : /* @__PURE__ */ jsx(Fragment, { children: B ?? /* @__PURE__ */ jsx(DefaultLoading, {}) });
284
+ }
285
+ function ActorSwitchDialog({ open: d, currentActor: B, targetActor: V, currentRealm: H, targetRealm: U, onConfirm: W, onCancel: G }) {
286
+ return /* @__PURE__ */ jsxs(Dialog, {
287
+ open: d,
288
+ onClose: G,
289
+ children: [
290
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Switch Application" }),
291
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(DialogContentText, { children: [
292
+ "You are about to switch from ",
293
+ /* @__PURE__ */ jsx("strong", { children: B }),
294
+ " to ",
295
+ /* @__PURE__ */ jsx("strong", { children: V }),
296
+ ".",
297
+ H !== U && H && /* @__PURE__ */ jsxs(Fragment, { children: [
298
+ /* @__PURE__ */ jsx("br", {}),
299
+ /* @__PURE__ */ jsx("br", {}),
300
+ "This will require you to log in again as the applications use different authentication realms."
301
+ ] })
302
+ ] }) }),
303
+ /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
304
+ onClick: G,
305
+ children: "Cancel"
306
+ }), /* @__PURE__ */ jsx(Button, {
307
+ onClick: W,
308
+ variant: "contained",
309
+ color: "primary",
310
+ children: "Switch"
311
+ })] })
312
+ ]
313
+ });
314
+ }
315
+ export { ActorAuthBoundary, ActorSwitchDialog, AuthConfigProvider, JudoAuthProvider, PrincipalProvider, buildOidcConfig, claimTypeToKey, clearAllRealmCache, clearRealmCache, createOidcOptions, getAuthConfig, getCachedRealmCount, getOrCreateUserManager, getSwitchConfigs, hasRealmInCache, isSameRealm, mapClaimsToPrincipal, useActorSwitch, useAuth, useAuthConfig, useAuthConfigOptional, useOidcAuthRequired, usePrincipal, usePrincipalOptional, useRequireAuth, validateOidcOptions };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["mapping: Record<ClaimType, string>","data: Record<string, unknown>"],"sources":["../src/config/auth-config.ts","../src/config/oidc-config.ts","../src/provider/auth-config-context.tsx","../src/provider/realm-cache.ts","../src/provider/judo-auth-provider.tsx","../src/provider/principal-context.tsx","../src/utils/claim-mapping.ts","../src/hooks/use-auth.ts","../src/hooks/use-require-auth.ts","../src/hooks/use-actor-switch.ts","../src/components/actor-auth-boundary.tsx","../src/components/actor-switch-dialog.tsx"],"sourcesContent":["import type { Application, ClaimType } from \"@judo/model-api\";\n\n/**\n * Mapping of a claim to an attribute.\n */\nexport interface ClaimMapping {\n\tclaimType: ClaimType;\n\tattributeName: string;\n}\n\n/**\n * Actor authentication configuration extracted from Application model.\n */\nexport interface ActorAuthConfig {\n\tactorName: string;\n\trequiresAuth: boolean;\n\trealm?: string;\n\tclientId?: string;\n\tclaims: ClaimMapping[];\n}\n\n/**\n * Extract authentication configuration from Application model.\n *\n * @param app - The Application model\n * @returns ActorAuthConfig with authentication requirements\n */\nexport function getAuthConfig(app: Application): ActorAuthConfig {\n\tconst requiresAuth = !!app.authentication;\n\n\tif (!requiresAuth) {\n\t\treturn {\n\t\t\tactorName: app.name,\n\t\t\trequiresAuth: false,\n\t\t\tclaims: [],\n\t\t};\n\t}\n\n\treturn {\n\t\tactorName: app.name,\n\t\trequiresAuth: true,\n\t\trealm: app.authentication!.realm,\n\t\tclientId: `${app.modelName}-${app.name}`,\n\t\tclaims: app.authentication!.claims.map((c) => ({\n\t\t\tclaimType: c.type,\n\t\t\tattributeName: c.attributeType.name,\n\t\t})),\n\t};\n}\n\n/**\n * Check if two actors share the same authentication realm.\n *\n * @param config1 - First actor's auth config\n * @param config2 - Second actor's auth config\n * @returns true if both share same realm or neither requires auth\n */\nexport function isSameRealm(config1: ActorAuthConfig, config2: ActorAuthConfig): boolean {\n\t// If neither requires auth, they effectively share the same \"realm\" (none)\n\tif (!config1.requiresAuth && !config2.requiresAuth) {\n\t\treturn true;\n\t}\n\n\t// If one requires auth and the other doesn't, different realms\n\tif (config1.requiresAuth !== config2.requiresAuth) {\n\t\treturn false;\n\t}\n\n\t// Both require auth - check realm equality\n\treturn config1.realm === config2.realm;\n}\n","import type { UserManagerSettings } from \"oidc-client-ts\";\nimport type { ActorAuthConfig } from \"./auth-config\";\n\n/**\n * Simplified OIDC configuration requiring only the provider URL.\n * All other fields have sensible defaults.\n *\n * The client ID is derived automatically from the active actor's Application.name\n * in the model — it is not configurable here.\n */\nexport interface OidcConfig {\n\t/** OIDC issuer base URL (e.g., 'https://auth.example.com'). The '/auth/realms/{realm}' path is appended from model. */\n\tissuerUrl: string;\n\t/** OAuth scopes. @default 'openid profile email' */\n\tscope?: string;\n\t/** Redirect URI after login. @default window.location.origin */\n\tredirectUri?: string;\n\t/** Redirect URI after logout. @default window.location.origin */\n\tpostLogoutRedirectUri?: string;\n}\n\n/**\n * Create full OidcOptions from simplified OidcConfig with sensible defaults.\n *\n * @param config - Simplified OIDC config (only issuerUrl required)\n * @returns Full OidcOptions with all fields populated\n */\nexport function createOidcOptions(config: OidcConfig): OidcOptions {\n\tconst origin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost:3000\";\n\treturn {\n\t\tissuerUrl: config.issuerUrl,\n\t\tredirectUri: config.redirectUri ?? origin,\n\t\tpostLogoutRedirectUri: config.postLogoutRedirectUri ?? origin,\n\t\tscope: config.scope,\n\t};\n}\n\n/**\n * Options for building OIDC configuration.\n */\nexport interface OidcOptions {\n\t/** Base URL for the OIDC issuer */\n\tissuerUrl: string;\n\t/** URI to redirect after login */\n\tredirectUri: string;\n\t/** URI to redirect after logout */\n\tpostLogoutRedirectUri: string;\n\t/** OAuth scopes (defaults to 'openid profile email') */\n\tscope?: string;\n\t/** Response type (defaults to 'code') */\n\tresponseType?: string;\n}\n\n/**\n * Build OIDC client configuration from ActorAuthConfig.\n *\n * @param config - Actor authentication configuration\n * @param options - OIDC options\n * @returns UserManagerSettings for oidc-client-ts\n * @throws Error if config doesn't require authentication\n */\nexport function buildOidcConfig(config: ActorAuthConfig, options: OidcOptions): UserManagerSettings {\n\tif (!config.requiresAuth) {\n\t\tthrow new Error(\"Cannot build OIDC config for unauthenticated actor\");\n\t}\n\n\tif (!config.realm) {\n\t\tthrow new Error(\"Realm is required for authenticated actor\");\n\t}\n\n\tif (!config.clientId) {\n\t\tthrow new Error(\"Client ID is required for authenticated actor (derived from Application.name)\");\n\t}\n\n\treturn {\n\t\tauthority: `${options.issuerUrl}/auth/realms/${config.realm}`,\n\t\tclient_id: config.clientId,\n\t\tredirect_uri: options.redirectUri,\n\t\tpost_logout_redirect_uri: options.postLogoutRedirectUri,\n\t\tscope: options.scope || \"openid profile email\",\n\t\tresponse_type: options.responseType || \"code\",\n\t\tautomaticSilentRenew: true,\n\t\tloadUserInfo: true,\n\t};\n}\n\n/**\n * Validate OIDC options.\n *\n * @param options - OIDC options to validate\n * @throws Error if options are invalid\n */\nexport function validateOidcOptions(options: OidcOptions): void {\n\tif (!options.issuerUrl) {\n\t\tthrow new Error(\"issuerUrl is required\");\n\t}\n\tif (!options.redirectUri) {\n\t\tthrow new Error(\"redirectUri is required\");\n\t}\n\tif (!options.postLogoutRedirectUri) {\n\t\tthrow new Error(\"postLogoutRedirectUri is required\");\n\t}\n\n\t// Validate URLs\n\tif (!URL.canParse(options.issuerUrl)) {\n\t\tthrow new Error(\"issuerUrl must be a valid URL\");\n\t}\n\n\tif (!URL.canParse(options.redirectUri)) {\n\t\tthrow new Error(\"redirectUri must be a valid URL\");\n\t}\n\n\tif (!URL.canParse(options.postLogoutRedirectUri)) {\n\t\tthrow new Error(\"postLogoutRedirectUri must be a valid URL\");\n\t}\n}\n","import { type ReactNode, createContext, useContext } from \"react\";\nimport type { ActorAuthConfig, OidcOptions } from \"../config\";\n\n/**\n * Context value for auth configuration.\n */\nexport interface AuthConfigContextType {\n\tconfig: ActorAuthConfig;\n\toidcOptions: OidcOptions;\n}\n\nconst AuthConfigContext = createContext<AuthConfigContextType | null>(null);\n\n/**\n * Hook to access auth configuration context.\n *\n * @returns AuthConfigContextType\n * @throws Error if used outside AuthConfigProvider\n */\nexport function useAuthConfig(): AuthConfigContextType {\n\tconst context = useContext(AuthConfigContext);\n\tif (!context) {\n\t\tthrow new Error(\"useAuthConfig must be used within AuthConfigProvider\");\n\t}\n\treturn context;\n}\n\n/**\n * Hook to access auth configuration context (optional).\n * Returns null if not within provider instead of throwing.\n *\n * @returns AuthConfigContextType | null\n */\nexport function useAuthConfigOptional(): AuthConfigContextType | null {\n\treturn useContext(AuthConfigContext);\n}\n\n/**\n * Props for AuthConfigProvider.\n */\nexport interface AuthConfigProviderProps {\n\tconfig: ActorAuthConfig;\n\toidcOptions: OidcOptions;\n\tchildren: ReactNode;\n}\n\n/**\n * Provider for auth configuration context.\n */\nexport function AuthConfigProvider({ config, oidcOptions, children }: AuthConfigProviderProps) {\n\treturn <AuthConfigContext.Provider value={{ config, oidcOptions }}>{children}</AuthConfigContext.Provider>;\n}\n","import { UserManager } from \"oidc-client-ts\";\nimport type { UserManagerSettings } from \"oidc-client-ts\";\n\n/**\n * Realm-based UserManager cache.\n * Actors sharing the same realm share the OIDC session.\n */\nconst realmProviderCache = new Map<string, UserManager>();\n\n/**\n * Get or create a UserManager for the given realm.\n * Uses caching to ensure actors with the same realm share sessions.\n *\n * @param realm - The realm identifier\n * @param config - UserManager configuration\n * @returns UserManager instance for the realm\n */\nexport function getOrCreateUserManager(realm: string, config: UserManagerSettings): UserManager {\n\tif (!realmProviderCache.has(realm)) {\n\t\trealmProviderCache.set(realm, new UserManager(config));\n\t}\n\treturn realmProviderCache.get(realm)!;\n}\n\n/**\n * Clear a specific realm from the cache.\n * Useful for testing or when a realm needs to be re-initialized.\n *\n * @param realm - The realm to clear\n */\nexport function clearRealmCache(realm: string): void {\n\trealmProviderCache.delete(realm);\n}\n\n/**\n * Clear all realms from the cache.\n * Useful for testing.\n */\nexport function clearAllRealmCache(): void {\n\trealmProviderCache.clear();\n}\n\n/**\n * Check if a realm exists in the cache.\n *\n * @param realm - The realm to check\n * @returns true if the realm is cached\n */\nexport function hasRealmInCache(realm: string): boolean {\n\treturn realmProviderCache.has(realm);\n}\n\n/**\n * Get the number of cached realms.\n * Useful for testing.\n *\n * @returns Number of cached realms\n */\nexport function getCachedRealmCount(): number {\n\treturn realmProviderCache.size;\n}\n","import { type ReactNode, useCallback, useMemo } from \"react\";\nimport { AuthProvider as OidcAuthProvider } from \"react-oidc-context\";\nimport type { ActorAuthConfig, OidcOptions } from \"../config\";\nimport { buildOidcConfig } from \"../config\";\nimport { AuthConfigProvider } from \"./auth-config-context\";\nimport { getOrCreateUserManager } from \"./realm-cache\";\n\n/**\n * Props for JudoAuthProvider.\n */\nexport interface JudoAuthProviderProps {\n\tconfig: ActorAuthConfig;\n\toidcOptions: OidcOptions;\n\tchildren: ReactNode;\n}\n\n/**\n * Auth provider that handles optional authentication.\n * If actor doesn't require auth, renders children directly.\n * If auth is required, wraps with OIDC provider.\n *\n * Actors sharing the same realm will share OIDC sessions.\n */\nexport function JudoAuthProvider({ config, oidcOptions, children }: JudoAuthProviderProps) {\n\t// After OIDC callback, strip ?code=...&state=... from the URL to prevent\n\t// the library from re-processing an already-used authorization code on refresh.\n\tconst onSigninCallback = useCallback(() => {\n\t\twindow.history.replaceState({}, document.title, window.location.pathname);\n\t}, []);\n\n\t// Wrap with auth config context regardless of auth requirement\n\tconst content = useMemo(() => {\n\t\t// No auth required - render directly\n\t\tif (!config.requiresAuth) {\n\t\t\treturn <>{children}</>;\n\t\t}\n\n\t\t// Get or create UserManager for this realm\n\t\tconst oidcConfig = buildOidcConfig(config, oidcOptions);\n\t\tconst userManager = getOrCreateUserManager(config.realm!, oidcConfig);\n\n\t\treturn (\n\t\t\t<OidcAuthProvider userManager={userManager} onSigninCallback={onSigninCallback}>\n\t\t\t\t{children}\n\t\t\t</OidcAuthProvider>\n\t\t);\n\t}, [config, oidcOptions, children, onSigninCallback]);\n\n\treturn (\n\t\t<AuthConfigProvider config={config} oidcOptions={oidcOptions}>\n\t\t\t{content}\n\t\t</AuthConfigProvider>\n\t);\n}\n","import { type ReactNode, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { PrincipalData } from \"../hooks/use-auth\";\n\n// ============================================\n// TYPES\n// ============================================\n\n/**\n * Context providing backend principal data with refresh/override capabilities.\n *\n * This is separate from `useAuth().principal` which provides OIDC-claim-mapped data.\n * `usePrincipal()` provides the **backend** principal fetched from `GET /~principal`.\n */\nexport interface PrincipalContextType {\n\t/** Backend principal data, or null if not yet fetched / not authenticated */\n\tprincipal: PrincipalData | null;\n\t/** Whether the principal is currently being fetched */\n\tisLoading: boolean;\n\t/** Re-fetch principal from the backend. Triggers a re-render of the subtree. */\n\trefreshPrincipal: () => Promise<void>;\n\t/** Override principal data locally. Pass null to clear. */\n\tsetPrincipal: (data: PrincipalData | null) => void;\n}\n\n/**\n * Props for PrincipalProvider.\n */\nexport interface PrincipalProviderProps {\n\t/**\n\t * Async function that fetches the principal from the backend.\n\t * If omitted, the provider will not auto-fetch and principal stays null.\n\t *\n\t * Typically wired as: `() => api.getPrincipal().then(r => r.data)`\n\t */\n\tfetchPrincipal?: () => Promise<Record<string, unknown>>;\n\tchildren: ReactNode;\n}\n\n// ============================================\n// CONTEXT\n// ============================================\n\nconst PrincipalContext = createContext<PrincipalContextType | null>(null);\n\n// ============================================\n// HOOKS\n// ============================================\n\n/**\n * Access the backend principal context.\n * Must be used within a PrincipalProvider.\n *\n * @throws Error if used outside PrincipalProvider\n */\nexport function usePrincipal(): PrincipalContextType {\n\tconst context = useContext(PrincipalContext);\n\tif (!context) {\n\t\tthrow new Error(\"usePrincipal must be used within a PrincipalProvider\");\n\t}\n\treturn context;\n}\n\n/**\n * Optionally access the backend principal context.\n * Returns null when used outside PrincipalProvider (safe for optional auth scenarios).\n */\nexport function usePrincipalOptional(): PrincipalContextType | null {\n\treturn useContext(PrincipalContext);\n}\n\n// ============================================\n// PROVIDER\n// ============================================\n\n/**\n * Provides backend principal state with auto-fetch, refresh, and local override.\n *\n * On mount, if `fetchPrincipal` is provided, the principal is fetched automatically.\n * Use `refreshPrincipal()` to re-fetch and `setPrincipal()` for local overrides.\n *\n * Place inside the auth boundary (after authentication is confirmed) and inside\n * the API provider (so `fetchPrincipal` can call API methods).\n */\nexport function PrincipalProvider({ fetchPrincipal, children }: PrincipalProviderProps) {\n\tconst [principal, setPrincipalState] = useState<PrincipalData | null>(null);\n\tconst [isLoading, setIsLoading] = useState(false);\n\tconst fetchRef = useRef(fetchPrincipal);\n\tfetchRef.current = fetchPrincipal;\n\n\tconst doFetch = useCallback(async () => {\n\t\tconst fn = fetchRef.current;\n\t\tif (!fn) return;\n\n\t\tsetIsLoading(true);\n\t\ttry {\n\t\t\tconst data = (await fn()) as PrincipalData;\n\t\t\tsetPrincipalState(data);\n\t\t} catch {\n\t\t\t// Fetch failed — principal stays null. Consumer can retry via refreshPrincipal().\n\t\t} finally {\n\t\t\tsetIsLoading(false);\n\t\t}\n\t}, []);\n\n\t// Auto-fetch on mount\n\tuseEffect(() => {\n\t\tvoid doFetch();\n\t}, [doFetch]);\n\n\tconst setPrincipal = useCallback((data: PrincipalData | null) => {\n\t\tsetPrincipalState(data);\n\t}, []);\n\n\tconst value = useMemo<PrincipalContextType>(\n\t\t() => ({\n\t\t\tprincipal,\n\t\t\tisLoading,\n\t\t\trefreshPrincipal: doFetch,\n\t\t\tsetPrincipal,\n\t\t}),\n\t\t[principal, isLoading, doFetch, setPrincipal]\n\t);\n\n\treturn <PrincipalContext.Provider value={value}>{children}</PrincipalContext.Provider>;\n}\n","import { ClaimType } from \"@judo/model-api\";\nimport type { ClaimMapping } from \"../config\";\n\n/**\n * Map ClaimType enum to OIDC claim key.\n *\n * @param type - ClaimType enum value\n * @returns OIDC claim key string\n */\nexport function claimTypeToKey(type: ClaimType): string {\n\tconst mapping: Record<ClaimType, string> = {\n\t\t[ClaimType.EMAIL]: \"email\",\n\t\t[ClaimType.USERNAME]: \"preferred_username\",\n\t\t[ClaimType.UNDEFINED]: \"\",\n\t};\n\treturn mapping[type] || \"\";\n}\n\n/**\n * Map OIDC claims profile to principal data using claim mappings.\n *\n * @param profile - OIDC user profile claims\n * @param mappings - Claim mappings from auth config\n * @returns Mapped principal data\n */\nexport function mapClaimsToPrincipal(\n\tprofile: Record<string, unknown> | undefined,\n\tmappings: ClaimMapping[]\n): Record<string, unknown> {\n\tif (!profile) {\n\t\treturn {};\n\t}\n\n\tconst data: Record<string, unknown> = {};\n\n\t// Map standard claims\n\tif (profile.email !== undefined) {\n\t\tdata.email = profile.email;\n\t}\n\tif (profile.name !== undefined) {\n\t\tdata.name = profile.name;\n\t}\n\tif (profile.preferred_username !== undefined) {\n\t\tdata.preferredUsername = profile.preferred_username;\n\t}\n\tif (profile.given_name !== undefined) {\n\t\tdata.givenName = profile.given_name;\n\t}\n\tif (profile.family_name !== undefined) {\n\t\tdata.familyName = profile.family_name;\n\t}\n\n\t// Map custom claims from config\n\tfor (const mapping of mappings) {\n\t\tconst claimKey = claimTypeToKey(mapping.claimType);\n\t\tif (claimKey && profile[claimKey] !== undefined) {\n\t\t\tdata[mapping.attributeName] = profile[claimKey];\n\t\t}\n\t}\n\n\treturn data;\n}\n","import { useMemo } from \"react\";\nimport { type AuthContextProps, useAuth as useOidcAuth } from \"react-oidc-context\";\nimport { useAuthConfigOptional } from \"../provider\";\nimport { mapClaimsToPrincipal } from \"../utils\";\n\n/**\n * Principal data derived from OIDC claims.\n */\nexport interface PrincipalData {\n\temail?: string;\n\tname?: string;\n\tpreferredUsername?: string;\n\tgivenName?: string;\n\tfamilyName?: string;\n\t[key: string]: unknown;\n}\n\n/**\n * Extended auth context with JUDO-specific additions.\n */\nexport interface JudoAuthContext {\n\t/** Whether authentication is required for this actor */\n\trequiresAuth: boolean;\n\t/** Current actor name */\n\tactorName: string;\n\t/** Mapped principal data from claims */\n\tprincipal: PrincipalData | null;\n\t/** Whether user is authenticated */\n\tisAuthenticated: boolean;\n\t/** Whether auth state is loading */\n\tisLoading: boolean;\n\t/** The active OIDC navigator (e.g., 'signinRedirect') or undefined when idle */\n\tactiveNavigator: string | undefined;\n\t/** The underlying OIDC user object */\n\tuser: AuthContextProps[\"user\"] | null;\n\t/** Trigger sign-in redirect */\n\tsigninRedirect: () => Promise<void>;\n\t/** Trigger sign-out redirect */\n\tsignoutRedirect: () => Promise<void>;\n\t/** Sign out silently */\n\tsignoutSilent: () => Promise<void>;\n\t/** Remove user from session */\n\tremoveUser: () => Promise<void>;\n\t/** OIDC error if any */\n\terror: Error | undefined;\n}\n\n/**\n * Stub auth context for unauthenticated actors.\n */\nfunction createUnauthenticatedContext(actorName: string): JudoAuthContext {\n\tconst noop = async () => {};\n\treturn {\n\t\trequiresAuth: false,\n\t\tactorName,\n\t\tprincipal: null,\n\t\tisAuthenticated: false,\n\t\tisLoading: false,\n\t\tactiveNavigator: undefined,\n\t\tuser: null,\n\t\tsigninRedirect: noop,\n\t\tsignoutRedirect: noop,\n\t\tsignoutSilent: noop,\n\t\tremoveUser: noop,\n\t\terror: undefined,\n\t};\n}\n\n/**\n * Extended auth hook with principal mapping.\n * Re-exports react-oidc-context with added JUDO functionality.\n *\n * @returns JudoAuthContext\n */\nexport function useAuth(): JudoAuthContext {\n\tconst authConfig = useAuthConfigOptional();\n\n\t// If no auth config, actor doesn't require authentication\n\tif (!authConfig) {\n\t\treturn createUnauthenticatedContext(\"unknown\");\n\t}\n\n\tconst { config } = authConfig;\n\n\t// If actor doesn't require auth, return stub context\n\tif (!config.requiresAuth) {\n\t\treturn createUnauthenticatedContext(config.actorName);\n\t}\n\n\t// Actor requires auth - use OIDC context\n\t// This hook call is conditionally safe because requiresAuth\n\t// determines whether JudoAuthProvider wraps with OidcAuthProvider\n\tconst oidcAuth = useOidcAuth();\n\n\tconst principal = useMemo<PrincipalData | null>(() => {\n\t\tif (!oidcAuth.user) {\n\t\t\treturn null;\n\t\t}\n\t\treturn mapClaimsToPrincipal(oidcAuth.user.profile as Record<string, unknown>, config.claims);\n\t}, [oidcAuth.user, config.claims]);\n\n\treturn {\n\t\trequiresAuth: config.requiresAuth,\n\t\tactorName: config.actorName,\n\t\tprincipal,\n\t\tisAuthenticated: oidcAuth.isAuthenticated,\n\t\tisLoading: oidcAuth.isLoading,\n\t\tactiveNavigator: oidcAuth.activeNavigator,\n\t\tuser: oidcAuth.user,\n\t\tsigninRedirect: () => oidcAuth.signinRedirect(),\n\t\tsignoutRedirect: () => oidcAuth.signoutRedirect(),\n\t\tsignoutSilent: () => oidcAuth.signoutSilent(),\n\t\tremoveUser: () => oidcAuth.removeUser(),\n\t\terror: oidcAuth.error,\n\t};\n}\n\n/**\n * Internal hook that must be called within OIDC provider.\n * Used by components that know auth is required.\n */\nexport function useOidcAuthRequired(): AuthContextProps {\n\treturn useOidcAuth();\n}\n","import { useEffect } from \"react\";\nimport { useAuth } from \"./use-auth\";\n\n/**\n * Guard hook that redirects to login if auth required but not authenticated.\n * Should be used in route/page guards.\n *\n * @example\n * ```tsx\n * function ProtectedPage() {\n * useRequireAuth();\n * return <PageContent />;\n * }\n * ```\n */\nexport function useRequireAuth(): void {\n\tconst { requiresAuth, isAuthenticated, isLoading, signinRedirect } = useAuth();\n\n\tuseEffect(() => {\n\t\tif (requiresAuth && !isLoading && !isAuthenticated) {\n\t\t\tsigninRedirect();\n\t\t}\n\t}, [requiresAuth, isLoading, isAuthenticated, signinRedirect]);\n}\n","import type { Application } from \"@judo/model-api\";\nimport { useCallback, useState } from \"react\";\nimport { type ActorAuthConfig, getAuthConfig, isSameRealm } from \"../config\";\nimport { useAuth } from \"./use-auth\";\n\n/**\n * Pending actor switch information.\n */\nexport interface PendingSwitch {\n\ttargetActor: string;\n\ttargetRealm?: string;\n\trequiresConfirmation: boolean;\n}\n\n/**\n * Result from useActorSwitch hook.\n */\nexport interface UseActorSwitchResult {\n\t/** Initiate switch to another actor */\n\tswitchActor: (actorName: string) => void;\n\t/** Pending switch awaiting confirmation (null if none) */\n\tpendingSwitch: PendingSwitch | null;\n\t/** Confirm the pending switch */\n\tconfirmSwitch: () => Promise<void>;\n\t/** Cancel the pending switch */\n\tcancelSwitch: () => void;\n}\n\n/**\n * Hook for managing actor switching with realm-aware confirmation.\n *\n * @param currentApp - Current active application\n * @param getApplication - Function to get application by actor name\n * @param setActiveApplication - Function to set active application\n * @returns UseActorSwitchResult\n */\nexport function useActorSwitch(\n\tcurrentApp: Application,\n\tgetApplication: (actorName: string) => Application,\n\tsetActiveApplication: (actorName: string) => void\n): UseActorSwitchResult {\n\tconst [pendingSwitch, setPendingSwitch] = useState<PendingSwitch | null>(null);\n\tconst { signoutRedirect, requiresAuth } = useAuth();\n\n\tconst currentConfig = getAuthConfig(currentApp);\n\n\tconst switchActor = useCallback(\n\t\t(actorName: string) => {\n\t\t\tconst targetApp = getApplication(actorName);\n\t\t\tconst targetConfig = getAuthConfig(targetApp);\n\n\t\t\t// Check if realm change requires confirmation\n\t\t\tconst requiresConfirmation = currentConfig.requiresAuth && !isSameRealm(currentConfig, targetConfig);\n\n\t\t\tif (requiresConfirmation) {\n\t\t\t\tsetPendingSwitch({\n\t\t\t\t\ttargetActor: actorName,\n\t\t\t\t\ttargetRealm: targetConfig.realm,\n\t\t\t\t\trequiresConfirmation: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Direct switch - same realm or no auth\n\t\t\t\tsetActiveApplication(actorName);\n\t\t\t}\n\t\t},\n\t\t[currentConfig, getApplication, setActiveApplication]\n\t);\n\n\tconst confirmSwitch = useCallback(async () => {\n\t\tif (!pendingSwitch) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Logout from current realm if authenticated\n\t\tif (requiresAuth) {\n\t\t\tawait signoutRedirect();\n\t\t}\n\n\t\t// Switch application\n\t\tsetActiveApplication(pendingSwitch.targetActor);\n\t\tsetPendingSwitch(null);\n\t}, [pendingSwitch, requiresAuth, signoutRedirect, setActiveApplication]);\n\n\tconst cancelSwitch = useCallback(() => {\n\t\tsetPendingSwitch(null);\n\t}, []);\n\n\treturn {\n\t\tswitchActor,\n\t\tpendingSwitch,\n\t\tconfirmSwitch,\n\t\tcancelSwitch,\n\t};\n}\n\n/**\n * Get current and target actor configs for switch dialog.\n *\n * @param currentApp - Current application\n * @param targetApp - Target application\n * @returns Object with both configs\n */\nexport function getSwitchConfigs(\n\tcurrentApp: Application,\n\ttargetApp: Application\n): { currentConfig: ActorAuthConfig; targetConfig: ActorAuthConfig } {\n\treturn {\n\t\tcurrentConfig: getAuthConfig(currentApp),\n\t\ttargetConfig: getAuthConfig(targetApp),\n\t};\n}\n","import { Box, CircularProgress } from \"@mui/material\";\nimport { type ReactNode, useEffect } from \"react\";\nimport { hasAuthParams } from \"react-oidc-context\";\nimport { useAuth } from \"../hooks\";\n\n/**\n * Props for ActorAuthBoundary.\n */\nexport interface ActorAuthBoundaryProps {\n\tchildren: ReactNode;\n\t/** Custom loading component */\n\tloadingComponent?: ReactNode;\n\t/**\n\t * When true, unauthenticated users see a guest page instead of being\n\t * redirected to the OIDC provider. Typically derived from\n\t * `Application.supportGuestAccess`.\n\t */\n\tsupportGuestAccess?: boolean;\n\t/**\n\t * Component rendered when guest access is enabled and the user is\n\t * not authenticated. When omitted, the default loading/redirect\n\t * behavior applies even if `supportGuestAccess` is true (the\n\t * calling layer should always provide a fallback).\n\t */\n\tguestComponent?: ReactNode;\n}\n\n/**\n * Default loading component.\n */\nfunction DefaultLoading() {\n\treturn (\n\t\t<Box display=\"flex\" justifyContent=\"center\" alignItems=\"center\" minHeight=\"100vh\">\n\t\t\t<CircularProgress />\n\t\t</Box>\n\t);\n}\n\n/**\n * Boundary component that gates children behind authentication.\n *\n * Mirrors react-oidc-context's `withAuthenticationRequired` HOC exactly:\n * skip redirect when callback params are present, auth is loading,\n * a navigator is active, or user is already authenticated.\n * Otherwise trigger `signinRedirect()` — the browser navigates away.\n *\n * When `supportGuestAccess` is true and `guestComponent` is provided,\n * unauthenticated users see the guest page instead of being redirected.\n *\n * The `JudoAuthProvider` handles callback processing and URL cleanup\n * via its `onSigninCallback` prop.\n */\nexport function ActorAuthBoundary({\n\tchildren,\n\tloadingComponent,\n\tsupportGuestAccess,\n\tguestComponent,\n}: ActorAuthBoundaryProps) {\n\tconst { requiresAuth, isAuthenticated, isLoading, activeNavigator, signinRedirect } = useAuth();\n\n\t// Determine if guest mode is active\n\tconst isGuestMode = Boolean(supportGuestAccess && guestComponent);\n\n\tuseEffect(() => {\n\t\t// In guest mode, never auto-redirect — the guest page has a sign-in button\n\t\tif (isGuestMode) return;\n\n\t\tif (!requiresAuth || hasAuthParams() || isLoading || activeNavigator || isAuthenticated) {\n\t\t\treturn;\n\t\t}\n\t\tvoid signinRedirect();\n\t}, [isGuestMode, requiresAuth, isLoading, activeNavigator, isAuthenticated, signinRedirect]);\n\n\tif (!requiresAuth || isAuthenticated) {\n\t\treturn <>{children}</>;\n\t}\n\n\t// Guest access: show guest page instead of loading/redirect\n\tif (isGuestMode && !isLoading) {\n\t\treturn <>{guestComponent}</>;\n\t}\n\n\treturn <>{loadingComponent ?? <DefaultLoading />}</>;\n}\n","import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from \"@mui/material\";\n\n/**\n * Props for ActorSwitchDialog.\n */\nexport interface ActorSwitchDialogProps {\n\t/** Whether dialog is open */\n\topen: boolean;\n\t/** Current actor name */\n\tcurrentActor: string;\n\t/** Target actor name to switch to */\n\ttargetActor: string;\n\t/** Current realm (if authenticated) */\n\tcurrentRealm?: string;\n\t/** Target realm (if requires auth) */\n\ttargetRealm?: string;\n\t/** Callback when user confirms switch */\n\tonConfirm: () => void;\n\t/** Callback when user cancels switch */\n\tonCancel: () => void;\n}\n\n/**\n * Confirmation dialog shown when switching actors between different realms.\n * Warns user about potential logout.\n *\n * @example\n * ```tsx\n * <ActorSwitchDialog\n * open={pendingSwitch !== null}\n * currentActor=\"Admin\"\n * targetActor=\"User\"\n * currentRealm=\"admin-realm\"\n * targetRealm=\"user-realm\"\n * onConfirm={confirmSwitch}\n * onCancel={cancelSwitch}\n * />\n * ```\n */\nexport function ActorSwitchDialog({\n\topen,\n\tcurrentActor,\n\ttargetActor,\n\tcurrentRealm,\n\ttargetRealm,\n\tonConfirm,\n\tonCancel,\n}: ActorSwitchDialogProps) {\n\tconst realmChange = currentRealm !== targetRealm;\n\tconst willLogout = realmChange && currentRealm;\n\n\treturn (\n\t\t<Dialog open={open} onClose={onCancel}>\n\t\t\t<DialogTitle>Switch Application</DialogTitle>\n\t\t\t<DialogContent>\n\t\t\t\t<DialogContentText>\n\t\t\t\t\tYou are about to switch from <strong>{currentActor}</strong> to <strong>{targetActor}</strong>.\n\t\t\t\t\t{willLogout && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\tThis will require you to log in again as the applications use different authentication realms.\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t</DialogContentText>\n\t\t\t</DialogContent>\n\t\t\t<DialogActions>\n\t\t\t\t<Button onClick={onCancel}>Cancel</Button>\n\t\t\t\t<Button onClick={onConfirm} variant=\"contained\" color=\"primary\">\n\t\t\t\t\tSwitch\n\t\t\t\t</Button>\n\t\t\t</DialogActions>\n\t\t</Dialog>\n\t);\n}\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { ReactNode } from 'react';
2
+ import { ActorAuthConfig, OidcOptions } from '../config';
3
+ /**
4
+ * Context value for auth configuration.
5
+ */
6
+ export interface AuthConfigContextType {
7
+ config: ActorAuthConfig;
8
+ oidcOptions: OidcOptions;
9
+ }
10
+ /**
11
+ * Hook to access auth configuration context.
12
+ *
13
+ * @returns AuthConfigContextType
14
+ * @throws Error if used outside AuthConfigProvider
15
+ */
16
+ export declare function useAuthConfig(): AuthConfigContextType;
17
+ /**
18
+ * Hook to access auth configuration context (optional).
19
+ * Returns null if not within provider instead of throwing.
20
+ *
21
+ * @returns AuthConfigContextType | null
22
+ */
23
+ export declare function useAuthConfigOptional(): AuthConfigContextType | null;
24
+ /**
25
+ * Props for AuthConfigProvider.
26
+ */
27
+ export interface AuthConfigProviderProps {
28
+ config: ActorAuthConfig;
29
+ oidcOptions: OidcOptions;
30
+ children: ReactNode;
31
+ }
32
+ /**
33
+ * Provider for auth configuration context.
34
+ */
35
+ export declare function AuthConfigProvider({ config, oidcOptions, children }: AuthConfigProviderProps): import("react/jsx-runtime").JSX.Element;
36
+ //# sourceMappingURL=auth-config-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-config-context.d.ts","sourceRoot":"","sources":["../../src/provider/auth-config-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,qBAAqB,CAMrD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,qBAAqB,GAAG,IAAI,CAEpE;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,uBAAuB,2CAE5F"}
@@ -0,0 +1,5 @@
1
+ export { JudoAuthProvider, type JudoAuthProviderProps } from './judo-auth-provider';
2
+ export { AuthConfigProvider, useAuthConfig, useAuthConfigOptional, type AuthConfigContextType, type AuthConfigProviderProps, } from './auth-config-context';
3
+ export { PrincipalProvider, usePrincipal, usePrincipalOptional, type PrincipalContextType, type PrincipalProviderProps, } from './principal-context';
4
+ export { getOrCreateUserManager, clearRealmCache, clearAllRealmCache, hasRealmInCache, getCachedRealmCount, } from './realm-cache';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EACN,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,mBAAmB,GACnB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { ActorAuthConfig, OidcOptions } from '../config';
3
+ /**
4
+ * Props for JudoAuthProvider.
5
+ */
6
+ export interface JudoAuthProviderProps {
7
+ config: ActorAuthConfig;
8
+ oidcOptions: OidcOptions;
9
+ children: ReactNode;
10
+ }
11
+ /**
12
+ * Auth provider that handles optional authentication.
13
+ * If actor doesn't require auth, renders children directly.
14
+ * If auth is required, wraps with OIDC provider.
15
+ *
16
+ * Actors sharing the same realm will share OIDC sessions.
17
+ */
18
+ export declare function JudoAuthProvider({ config, oidcOptions, children }: JudoAuthProviderProps): import("react/jsx-runtime").JSX.Element;
19
+ //# sourceMappingURL=judo-auth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"judo-auth-provider.d.ts","sourceRoot":"","sources":["../../src/provider/judo-auth-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAwB,MAAM,OAAO,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAK9D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,qBAAqB,2CA8BxF"}