@orsetra/shared-auth 1.1.5 → 1.1.7
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.
- package/ZitadelProvider.tsx +3 -6
- package/index.ts +2 -1
- package/package.json +1 -1
- package/services/zitadel.auth.service.ts +30 -1
package/ZitadelProvider.tsx
CHANGED
|
@@ -24,6 +24,7 @@ const ZitadelContext = createContext<ZitadelContextType | undefined>(undefined)
|
|
|
24
24
|
export interface ZitadelProviderProps {
|
|
25
25
|
children: ReactNode
|
|
26
26
|
config: ZitadelConfig
|
|
27
|
+
/** Render the action button shown inside the session-expired modal. Receives the sign-in handler. */
|
|
27
28
|
renderSessionExpiredAction?: (onReauthenticate: () => void) => ReactNode
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -42,15 +43,11 @@ export function ZitadelProvider({ children, config, renderSessionExpiredAction }
|
|
|
42
43
|
try {
|
|
43
44
|
ZitadelAuthService.configureAuth(config)
|
|
44
45
|
ZitadelAuthService.onSessionExpired = () => setSessionExpired(true)
|
|
46
|
+
ZitadelAuthService.onUserSignedOut = () => ZitadelAuthService.signIn()
|
|
45
47
|
setIsConfigured(true)
|
|
46
48
|
|
|
47
49
|
const isAuthenticated = await ZitadelAuthService.isAuthenticated()
|
|
48
|
-
|
|
49
|
-
await ZitadelAuthService.signIn()
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const currentUser = await ZitadelAuthService.getUser()
|
|
50
|
+
const currentUser = isAuthenticated ? await ZitadelAuthService.getUser() : null
|
|
54
51
|
setUser(currentUser)
|
|
55
52
|
} catch (error) {
|
|
56
53
|
console.error("Failed to configure Zitadel auth:", error)
|
package/index.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
export { ZitadelProvider, useZitadel } from './ZitadelProvider'
|
|
3
3
|
export type { ZitadelProviderProps } from './ZitadelProvider'
|
|
4
4
|
export { ProtectedRoute } from './ProtectedRoute'
|
|
5
|
-
export { ZitadelAuthService } from './services/zitadel.auth.service'
|
|
5
|
+
export { ZitadelAuthService, decodeJwt, isJwtExpired } from './services/zitadel.auth.service'
|
|
6
|
+
export type { JwtPayload } from './services/zitadel.auth.service'
|
|
6
7
|
export { createAuthConfig } from './config/zitadel.config'
|
|
7
8
|
export type { ZitadelConfig } from './config/zitadel.config'
|
|
8
9
|
|
package/package.json
CHANGED
|
@@ -5,6 +5,28 @@ import { ZitadelConfig, createAuthConfig } from '../config/zitadel.config';
|
|
|
5
5
|
|
|
6
6
|
export type { ZitadelConfig };
|
|
7
7
|
|
|
8
|
+
export interface JwtPayload {
|
|
9
|
+
exp?: number
|
|
10
|
+
iat?: number
|
|
11
|
+
sub?: string
|
|
12
|
+
[key: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function decodeJwt(token: string): JwtPayload {
|
|
16
|
+
const payload = token.split('.')[1]
|
|
17
|
+
if (!payload) throw new Error('Invalid JWT: missing payload segment')
|
|
18
|
+
return JSON.parse(atob(payload)) as JwtPayload
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isJwtExpired(token: string): boolean {
|
|
22
|
+
try {
|
|
23
|
+
const { exp } = decodeJwt(token)
|
|
24
|
+
return typeof exp !== 'number' || exp <= Math.floor(Date.now() / 1000)
|
|
25
|
+
} catch {
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
export interface ZitadelAuth {
|
|
9
31
|
authorize(): Promise<void>;
|
|
10
32
|
signout(): Promise<void>;
|
|
@@ -46,6 +68,9 @@ function createZitadelAuth(zitadelConfig: ZitadelConfig): ZitadelAuth {
|
|
|
46
68
|
localStorage.removeItem(key);
|
|
47
69
|
}
|
|
48
70
|
});
|
|
71
|
+
// Session invalidated server-side (revocation, sign-out from another tab, IDP session ended)
|
|
72
|
+
// → redirect immediately, no modal
|
|
73
|
+
ZitadelAuthService.onUserSignedOut?.();
|
|
49
74
|
});
|
|
50
75
|
|
|
51
76
|
userManager.events.addAccessTokenExpired(() => {
|
|
@@ -73,7 +98,10 @@ function createZitadelAuth(zitadelConfig: ZitadelConfig): ZitadelAuth {
|
|
|
73
98
|
|
|
74
99
|
export class ZitadelAuthService {
|
|
75
100
|
private static zitadelAuth: ZitadelAuth | null = null;
|
|
101
|
+
/** Fired when the access token expires and silent renew fails — show a modal. */
|
|
76
102
|
static onSessionExpired: (() => void) | null = null;
|
|
103
|
+
/** Fired when the IDP invalidates the session (server logout, revocation, other tab sign-out) — redirect immediately. */
|
|
104
|
+
static onUserSignedOut: (() => void) | null = null;
|
|
77
105
|
|
|
78
106
|
static configureAuth(config: ZitadelConfig) {
|
|
79
107
|
this.zitadelAuth = createZitadelAuth(config);
|
|
@@ -148,7 +176,8 @@ export class ZitadelAuthService {
|
|
|
148
176
|
|
|
149
177
|
static async isAuthenticated(): Promise<boolean> {
|
|
150
178
|
const user = await this.getUser();
|
|
151
|
-
|
|
179
|
+
if (!user?.access_token) return false;
|
|
180
|
+
return !isJwtExpired(user.access_token);
|
|
152
181
|
}
|
|
153
182
|
|
|
154
183
|
static async getTokenRemainingTime(): Promise<number> {
|