@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.
@@ -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
- if (!isAuthenticated) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orsetra/shared-auth",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Shared authentication utilities for Orsetra platform using Zitadel",
5
5
  "main": "./index.ts",
6
6
  "types": "./index.ts",
@@ -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
- return user !== null && !user.expired;
179
+ if (!user?.access_token) return false;
180
+ return !isJwtExpired(user.access_token);
152
181
  }
153
182
 
154
183
  static async getTokenRemainingTime(): Promise<number> {