@authaction/web-sdk 0.1.0 → 0.1.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vue/index.ts","../../src/vue/plugin.ts","../../src/pkce.ts","../../src/storage.ts","../../src/client.ts","../../src/vue/composables.ts","../../src/vue/guard.ts","../../src/utils.ts"],"sourcesContent":["export { createAuthAction, AUTH_ACTION_KEY } from './plugin';\nexport type { AuthActionPlugin } from './plugin';\nexport {\n useAuthAction,\n useIsAuthenticated,\n useAuthLoading,\n useUser,\n useGetAccessToken,\n} from './composables';\nexport { createAuthGuard } from './guard';\nexport { hasAuthParams } from '../utils';\n","import { App, InjectionKey, reactive, readonly } from 'vue';\nimport { AuthActionClient } from '../client';\nimport type {\n AuthActionClientConfig,\n AuthState,\n GetAccessTokenOptions,\n LoginOptions,\n LoginWithPopupOptions,\n LogoutOptions,\n RedirectCallbackResult,\n} from '../types';\n\nexport const AUTH_ACTION_KEY: InjectionKey<AuthActionPlugin> = Symbol('AuthAction');\n\nexport interface AuthActionPlugin {\n readonly state: Readonly<AuthState>;\n loginWithRedirect(options?: LoginOptions): Promise<void>;\n loginWithPopup(options?: LoginWithPopupOptions): Promise<void>;\n handleRedirectCallback(url?: string): Promise<RedirectCallbackResult>;\n getAccessToken(options?: GetAccessTokenOptions): Promise<string>;\n logout(options?: LogoutOptions): Promise<void>;\n /**\n * Clear the local session without hitting the server's end-session endpoint.\n * Use this on 401 API responses where the server already invalidated the session.\n */\n removeUser(): void;\n install(app: App): void;\n}\n\n/**\n * Creates an AuthAction Vue plugin. Pass the returned value to `app.use()`.\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createAuthAction } from '@authaction/web-sdk/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n * app.use(createAuthAction({\n * domain: 'myapp.eu.authaction.com',\n * clientId: 'your-client-id',\n * redirectUri: 'http://localhost:5173/callback',\n * }));\n * app.mount('#app');\n * ```\n */\nexport function createAuthAction(config: AuthActionClientConfig): AuthActionPlugin {\n const client = new AuthActionClient(config);\n const reactiveState = reactive<AuthState>(client.getState());\n\n const plugin: AuthActionPlugin = {\n get state() {\n return readonly(reactiveState) as Readonly<AuthState>;\n },\n loginWithRedirect: (options?) => client.loginWithRedirect(options),\n loginWithPopup: (options?) => client.loginWithPopup(options),\n handleRedirectCallback: (url?) => client.handleRedirectCallback(url),\n getAccessToken: (options?) => client.getAccessToken(options),\n logout: (options?) => client.logout(options),\n removeUser: () => client.removeUser(),\n install(app: App) {\n client.onStateChange((s) => Object.assign(reactiveState, s));\n app.provide(AUTH_ACTION_KEY, plugin);\n },\n };\n\n return plugin;\n}\n","/** Generate a cryptographically random string for PKCE code_verifier or state */\nexport function generateRandom(length = 64): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join('');\n}\n\n/** base64url-encode a buffer (no padding, url-safe) */\nfunction base64urlEncode(buffer: ArrayBuffer): string {\n return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\n/** Compute the PKCE code_challenge from a code_verifier using S256 */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoded = new TextEncoder().encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', encoded);\n return base64urlEncode(digest);\n}\n\n/** Decode a JWT payload without verifying the signature */\nexport function decodeJwtPayload(token: string): Record<string, unknown> {\n const parts = token.split('.');\n if (parts.length !== 3) throw new Error('Invalid JWT format');\n const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n try {\n return JSON.parse(atob(payload));\n } catch {\n throw new Error('Failed to decode JWT payload');\n }\n}\n","import { TokenSet } from \"./types\";\n\n// ── PKCE transaction store ────────────────────────────────────────────────────\n// Must survive the redirect to /authorize and back, so always uses sessionStorage.\n\nconst PKCE_KEY = \"__authaction_pkce__\";\n\ninterface PkceTransaction {\n state: string;\n codeVerifier: string;\n redirectUri: string;\n appState?: Record<string, unknown>;\n}\n\nconst ss = (): Storage | null =>\n typeof sessionStorage !== \"undefined\" ? sessionStorage : null;\n\nexport const pkceStore = {\n save(tx: PkceTransaction): void {\n ss()?.setItem(PKCE_KEY, JSON.stringify(tx));\n },\n get(): PkceTransaction | null {\n const raw = ss()?.getItem(PKCE_KEY) ?? null;\n return raw ? (JSON.parse(raw) as PkceTransaction) : null;\n },\n clear(): void {\n ss()?.removeItem(PKCE_KEY);\n },\n};\n\n// ── Token cache ───────────────────────────────────────────────────────────────\n\nconst TOKEN_KEY = \"__authaction_tokens__\";\n\ntype StorageBackend = \"memory\" | \"localstorage\" | \"sessionstorage\";\n\nexport class TokenCache {\n private memStore: TokenSet | null = null;\n private backend: StorageBackend;\n\n constructor(backend: StorageBackend = \"memory\") {\n this.backend = backend;\n }\n\n get(): TokenSet | null {\n if (this.backend === \"memory\") return this.memStore;\n const raw = this.getStore()?.getItem(TOKEN_KEY) ?? null;\n return raw ? (JSON.parse(raw) as TokenSet) : null;\n }\n\n set(tokens: TokenSet): void {\n if (this.backend === \"memory\") {\n this.memStore = tokens;\n return;\n }\n this.getStore()?.setItem(TOKEN_KEY, JSON.stringify(tokens));\n }\n\n clear(): void {\n this.memStore = null;\n if (this.backend !== \"memory\") this.getStore()?.removeItem(TOKEN_KEY);\n }\n\n private getStore(): Storage | null {\n if (this.backend === \"localstorage\") {\n return typeof localStorage !== \"undefined\" ? localStorage : null;\n }\n return ss();\n }\n}\n","import { generateRandom, generateCodeChallenge, decodeJwtPayload } from './pkce';\nimport { pkceStore, TokenCache } from './storage';\nimport {\n AuthActionClientConfig,\n AuthState,\n GetAccessTokenOptions,\n LoginOptions,\n LoginWithPopupOptions,\n LogoutOptions,\n RedirectCallbackResult,\n StateChangeCallback,\n TokenSet,\n UnsubscribeFn,\n User,\n UserProfile,\n} from './types';\n\nconst DEFAULT_SCOPE = 'openid profile email';\n// Refresh the access token 60 seconds before it expires\nconst REFRESH_BUFFER_SECONDS = 60;\n\nexport class AuthActionClient {\n private readonly cfg: Required<Pick<AuthActionClientConfig, 'domain' | 'clientId' | 'redirectUri'>> &\n AuthActionClientConfig;\n private readonly cache: TokenCache;\n private readonly listeners = new Set<StateChangeCallback>();\n\n private state: AuthState = { isAuthenticated: false, isLoading: true, user: undefined, error: undefined };\n\n constructor(config: AuthActionClientConfig) {\n this.cfg = config as typeof this.cfg;\n this.cache = new TokenCache(config.cacheLocation ?? 'memory');\n // Restore state from cache on init (non-blocking)\n void this.loadStateFromCache();\n }\n\n // ── Login ────────────────────────────────────────────────────────────────────\n\n async loginWithRedirect(options: LoginOptions = {}): Promise<void> {\n this.setState({ ...this.state, activeNavigator: 'loginWithRedirect' });\n try {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({\n state,\n codeVerifier,\n redirectUri: this.cfg.redirectUri,\n appState: options.appState,\n });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n this.navigate(`https://${this.cfg.domain}/oauth2/authorize?${params}`);\n } catch (err) {\n this.setState({\n isAuthenticated: this.state.isAuthenticated,\n isLoading: false,\n user: this.state.user,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n throw err;\n }\n }\n\n /** Opens AuthAction login in a popup window instead of a full redirect */\n async loginWithPopup(options: LoginWithPopupOptions = {}): Promise<void> {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({ state, codeVerifier, redirectUri: this.cfg.redirectUri, appState: options.appState });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n const popup = options.popup ?? window.open(\n `https://${this.cfg.domain}/oauth2/authorize?${params}`,\n 'authaction:login',\n 'width=480,height=640,left=100,top=100',\n );\n\n if (!popup) throw new Error('Popup was blocked. Allow popups for this site and try again.');\n\n await new Promise<void>((resolve, reject) => {\n const listener = async (event: MessageEvent) => {\n if (event.origin !== window.location.origin) return;\n if (!event.data?.type?.startsWith('authaction:')) return;\n\n window.removeEventListener('message', listener);\n\n if (event.data.type === 'authaction:callback') {\n try {\n const url = new URL(event.data.url);\n await this.exchangeCodeFromUrl(url);\n resolve();\n } catch (err) {\n reject(err);\n }\n } else if (event.data.type === 'authaction:error') {\n reject(new Error(event.data.error));\n }\n };\n window.addEventListener('message', listener);\n });\n }\n\n // ── Callback ─────────────────────────────────────────────────────────────────\n\n /**\n * Call this on the redirect callback page (e.g. /callback).\n * Exchanges the authorization code for tokens and returns the original appState.\n */\n async handleRedirectCallback(url?: string): Promise<RedirectCallbackResult> {\n const callbackUrl = new URL(url ?? window.location.href);\n const appState = await this.exchangeCodeFromUrl(callbackUrl);\n\n // Clean the code/state from the URL without a page reload\n const clean = new URL(window.location.href);\n clean.searchParams.delete('code');\n clean.searchParams.delete('state');\n window.history.replaceState({}, document.title, clean.toString());\n\n return { appState };\n }\n\n /**\n * Call this from the popup callback page to relay the URL back to the opener.\n * Place this call in the script that runs on your redirectUri page when in popup mode.\n */\n static handlePopupCallback(url?: string): void {\n if (!window.opener) return;\n window.opener.postMessage(\n { type: 'authaction:callback', url: url ?? window.location.href },\n window.location.origin,\n );\n window.close();\n }\n\n // ── Auth state ────────────────────────────────────────────────────────────────\n\n async isAuthenticated(): Promise<boolean> {\n const tokens = this.cache.get();\n if (!tokens) return false;\n // Auto-refresh if near expiry\n if (this.isExpired(tokens)) {\n try {\n await this.refreshTokens();\n } catch {\n return false;\n }\n }\n return true;\n }\n\n async getUser<T extends User = User>(): Promise<T | undefined> {\n if (!(await this.isAuthenticated())) return undefined;\n const tokens = this.cache.get();\n if (!tokens?.id_token) return undefined;\n try {\n return decodeJwtPayload(tokens.id_token) as unknown as T;\n } catch {\n return undefined;\n }\n }\n\n // ── Tokens ────────────────────────────────────────────────────────────────────\n\n /**\n * Returns a valid access token, refreshing automatically if needed.\n * Use this as the Bearer token for API calls including the AuthAction Files service.\n *\n * @example\n * const token = await client.getAccessToken();\n * fetch('/api/v1/files', { headers: { Authorization: `Bearer ${token}` } });\n */\n async getAccessToken(options: GetAccessTokenOptions = {}): Promise<string> {\n let tokens = this.cache.get();\n\n if (!tokens) throw new Error('Not authenticated — call loginWithRedirect() first');\n\n if (options.forceRefresh || this.isExpired(tokens)) {\n tokens = await this.refreshTokens();\n }\n\n return tokens.access_token;\n }\n\n // ── Logout ────────────────────────────────────────────────────────────────────\n\n async logout(options: LogoutOptions = {}): Promise<void> {\n this.cache.clear();\n\n if (options.federated === false) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined, activeNavigator: 'logout' });\n\n const returnTo = options.returnTo ?? this.cfg.postLogoutRedirectUri;\n const params = new URLSearchParams({\n client_id: options.clientId ?? this.cfg.clientId,\n ...(returnTo ? { post_logout_redirect_uri: returnTo } : {}),\n });\n\n this.navigate(`https://${this.cfg.domain}/oidc/logout?${params}`);\n }\n\n /**\n * Clears the local session (tokens + state) without hitting the server's end-session endpoint.\n * Use this to handle 401 responses from APIs where the server already considers the session gone.\n */\n removeUser(): void {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n\n // ── State subscriptions ────────────────────────────────────────────────────────\n\n onStateChange(callback: StateChangeCallback): UnsubscribeFn {\n this.listeners.add(callback);\n // Emit current state immediately\n callback(this.state);\n return () => this.listeners.delete(callback);\n }\n\n getState(): AuthState {\n return { ...this.state };\n }\n\n // ── Private ───────────────────────────────────────────────────────────────────\n\n private async exchangeCodeFromUrl(url: URL): Promise<Record<string, unknown> | undefined> {\n const code = url.searchParams.get('code');\n const returnedState = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n if (error) throw new Error(errorDescription ?? error);\n if (!code) throw new Error('No authorization code in callback URL');\n\n const tx = pkceStore.get();\n pkceStore.clear();\n\n if (!tx) throw new Error('No PKCE transaction found — did the login session expire?');\n if (tx.state !== returnedState) throw new Error('State mismatch — possible CSRF attack');\n\n const tokens = await this.exchangeCode(code, tx.codeVerifier, tx.redirectUri);\n this.cache.set(tokens);\n\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(tokens), error: undefined });\n\n return tx.appState;\n }\n\n private async exchangeCode(code: string, codeVerifier: string, redirectUri: string): Promise<TokenSet> {\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.cfg.clientId,\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}));\n throw new Error(err.error_description ?? err.error ?? 'Token exchange failed');\n }\n\n const data = await res.json();\n return this.normaliseTokenResponse(data);\n }\n\n private async refreshTokens(): Promise<TokenSet> {\n const tokens = this.cache.get();\n if (!tokens?.refresh_token) throw new Error('No refresh token available');\n\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.cfg.clientId,\n refresh_token: tokens.refresh_token,\n }),\n });\n\n if (!res.ok) {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n throw new Error('Token refresh failed — user must re-authenticate');\n }\n\n const data = await res.json();\n const refreshed = this.normaliseTokenResponse(data);\n this.cache.set(refreshed);\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(refreshed), error: undefined });\n return refreshed;\n }\n\n private normaliseTokenResponse(data: Record<string, unknown>): TokenSet {\n const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : 3600;\n return {\n access_token: data.access_token as string,\n id_token: data.id_token as string | undefined,\n refresh_token: data.refresh_token as string | undefined,\n scope: data.scope as string | undefined,\n expires_at: Math.floor(Date.now() / 1000) + expiresIn,\n };\n }\n\n private isExpired(tokens: TokenSet): boolean {\n return tokens.expires_at - REFRESH_BUFFER_SECONDS < Math.floor(Date.now() / 1000);\n }\n\n private async loadStateFromCache(): Promise<void> {\n const tokens = this.cache.get();\n if (!tokens) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n try {\n if (this.isExpired(tokens)) await this.refreshTokens();\n const cached = this.cache.get();\n this.setState({ isAuthenticated: true, isLoading: false, user: cached ? this.buildUser(cached) : undefined, error: undefined });\n } catch {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n }\n\n private buildUser(tokens: TokenSet): User | undefined {\n if (!tokens.id_token) return undefined;\n try {\n const claims = decodeJwtPayload(tokens.id_token) as User;\n const user: User = { ...claims, access_token: tokens.access_token };\n const profile: UserProfile = {\n sub: user.sub,\n name: user.name,\n email: user.email,\n email_verified: user.email_verified,\n picture: user.picture,\n };\n // Copy any extra claims from the ID token into profile\n for (const key of Object.keys(user)) {\n if (!(key in profile) && key !== 'access_token' && key !== 'profile') {\n profile[key] = user[key];\n }\n }\n user.profile = profile;\n return user;\n } catch {\n return undefined;\n }\n }\n\n /** Extracted for testability — spy on this method to capture redirect URLs */\n protected navigate(url: string): void {\n window.location.assign(url);\n }\n\n private setState(next: AuthState): void {\n this.state = next;\n this.notifyListeners(next);\n }\n\n private notifyListeners(state: AuthState): void {\n this.state = state;\n this.listeners.forEach((cb) => cb(state));\n }\n}\n","import { computed, inject } from 'vue';\nimport { AUTH_ACTION_KEY } from './plugin';\nimport type { AuthActionPlugin } from './plugin';\nimport type { GetAccessTokenOptions, User } from '../types';\n\n/**\n * Primary composable — returns the full auth instance with state and all methods.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useAuthAction } from '@authaction/web-sdk/vue';\n *\n * const { state, loginWithRedirect, logout } = useAuthAction();\n * </script>\n * ```\n */\nexport function useAuthAction(): AuthActionPlugin {\n const auth = inject(AUTH_ACTION_KEY);\n if (!auth) {\n throw new Error(\n 'useAuthAction() must be called inside a component under a Vue app with the AuthAction plugin installed. ' +\n 'Call app.use(createAuthAction({ domain, clientId, redirectUri })) in main.ts.',\n );\n }\n return auth;\n}\n\n/** Reactive computed ref that is true when the user is authenticated */\nexport function useIsAuthenticated() {\n const auth = useAuthAction();\n return computed(() => auth.state.isAuthenticated);\n}\n\n/** Reactive computed ref that is true while the SDK is resolving initial auth state */\nexport function useAuthLoading() {\n const auth = useAuthAction();\n return computed(() => auth.state.isLoading);\n}\n\n/** Reactive computed ref with the current user profile, or undefined when not authenticated */\nexport function useUser<T extends User = User>() {\n const auth = useAuthAction();\n return computed(() => auth.state.user as T | undefined);\n}\n\n/**\n * Returns a function that fetches a valid access token on demand.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useGetAccessToken } from '@authaction/web-sdk/vue';\n *\n * const getToken = useGetAccessToken();\n *\n * async function uploadFile(file: File) {\n * const token = await getToken();\n * await fetch('/api/v1/files/upload', {\n * method: 'POST',\n * headers: { Authorization: `Bearer ${token}` },\n * body: file,\n * });\n * }\n * </script>\n * ```\n */\nexport function useGetAccessToken() {\n const { getAccessToken } = useAuthAction();\n return (options?: GetAccessTokenOptions) => getAccessToken(options);\n}\n","import { watch } from 'vue';\nimport type { NavigationGuardWithThis } from 'vue-router';\nimport type { AuthActionPlugin } from './plugin';\n\n/**\n * Creates a Vue Router navigation guard that redirects unauthenticated users to login.\n * Waits for the SDK to finish initialising before checking auth state.\n *\n * @example\n * ```ts\n * // router/index.ts\n * import { createRouter } from 'vue-router';\n * import { createAuthGuard } from '@authaction/web-sdk/vue';\n * import { auth } from '../main'; // the createAuthAction() instance\n *\n * const router = createRouter({ ... });\n * router.beforeEach(createAuthGuard(auth));\n * ```\n */\nexport function createAuthGuard(auth: AuthActionPlugin): NavigationGuardWithThis<undefined> {\n return async (to) => {\n if (auth.state.isLoading) {\n await new Promise<void>((resolve) => {\n const stop = watch(\n () => auth.state.isLoading,\n (loading) => {\n if (!loading) {\n stop();\n resolve();\n }\n },\n );\n });\n }\n\n if (auth.state.isAuthenticated) return true;\n\n await auth.loginWithRedirect({ appState: { returnTo: to.fullPath } });\n return false;\n };\n}\n","/**\n * Returns true if the given URL (or window.location) contains OAuth2 callback\n * params — i.e. the authorization server has redirected back with a code or error.\n * Mirrors react-oidc-context's hasAuthParams() for drop-in compatibility.\n */\nexport function hasAuthParams(url?: string): boolean {\n const search = url ? new URL(url).search : window.location.search;\n const params = new URLSearchParams(search);\n return params.has('code') || params.has('error');\n}\n"],"mappings":"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","names":["vue_exports","__export","AUTH_ACTION_KEY","createAuthAction","createAuthGuard","hasAuthParams","useAuthAction","useAuthLoading","useGetAccessToken","useIsAuthenticated","useUser","__toCommonJS","import_vue","generateRandom","length","chars","array","byte","base64urlEncode","buffer","generateCodeChallenge","verifier","encoded","digest","decodeJwtPayload","token","parts","payload","PKCE_KEY","ss","pkceStore","tx","raw","TOKEN_KEY","TokenCache","backend","tokens","DEFAULT_SCOPE","REFRESH_BUFFER_SECONDS","AuthActionClient","config","TokenCache","options","state","generateRandom","codeVerifier","codeChallenge","generateCodeChallenge","pkceStore","params","err","resolve","reject","listener","event","url","callbackUrl","appState","clean","tokens","decodeJwtPayload","returnTo","callback","code","returnedState","error","errorDescription","tx","redirectUri","res","data","refreshed","expiresIn","cached","user","profile","key","next","cb","AUTH_ACTION_KEY","createAuthAction","config","client","AuthActionClient","reactiveState","plugin","options","url","app","s","import_vue","useAuthAction","auth","AUTH_ACTION_KEY","useIsAuthenticated","useAuthLoading","useUser","useGetAccessToken","getAccessToken","options","import_vue","createAuthGuard","auth","to","resolve","stop","loading","hasAuthParams","url","search","params"]}
1
+ {"version":3,"sources":["../../src/vue/index.ts","../../src/vue/plugin.ts","../../src/pkce.ts","../../src/storage.ts","../../src/client.ts","../../src/vue/composables.ts","../../src/vue/guard.ts","../../src/utils.ts"],"sourcesContent":["export { createAuthAction, AUTH_ACTION_KEY } from './plugin';\nexport type { AuthActionPlugin } from './plugin';\nexport {\n useAuthAction,\n useIsAuthenticated,\n useAuthLoading,\n useUser,\n useGetAccessToken,\n} from './composables';\nexport { createAuthGuard } from './guard';\nexport { hasAuthParams } from '../utils';\n","import { App, InjectionKey, reactive, readonly } from 'vue';\nimport { AuthActionClient } from '../client';\nimport type {\n AuthActionClientConfig,\n AuthState,\n GetAccessTokenOptions,\n LoginOptions,\n LoginWithPopupOptions,\n LogoutOptions,\n RedirectCallbackResult,\n} from '../types';\n\nexport const AUTH_ACTION_KEY: InjectionKey<AuthActionPlugin> = Symbol('AuthAction');\n\nexport interface AuthActionPlugin {\n readonly state: Readonly<AuthState>;\n loginWithRedirect(options?: LoginOptions): Promise<void>;\n loginWithPopup(options?: LoginWithPopupOptions): Promise<void>;\n handleRedirectCallback(url?: string): Promise<RedirectCallbackResult>;\n getAccessToken(options?: GetAccessTokenOptions): Promise<string>;\n logout(options?: LogoutOptions): Promise<void>;\n /**\n * Clear the local session without hitting the server's end-session endpoint.\n * Use this on 401 API responses where the server already invalidated the session.\n */\n removeUser(): void;\n install(app: App): void;\n}\n\n/**\n * Creates an AuthAction Vue plugin. Pass the returned value to `app.use()`.\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue';\n * import { createAuthAction } from '@authaction/web-sdk/vue';\n * import App from './App.vue';\n *\n * const app = createApp(App);\n * app.use(createAuthAction({\n * domain: 'myapp.eu.authaction.com',\n * clientId: 'your-client-id',\n * redirectUri: 'http://localhost:5173/callback',\n * }));\n * app.mount('#app');\n * ```\n */\nexport function createAuthAction(config: AuthActionClientConfig): AuthActionPlugin {\n const client = new AuthActionClient(config);\n const reactiveState = reactive<AuthState>(client.getState());\n\n const plugin: AuthActionPlugin = {\n get state() {\n return readonly(reactiveState) as Readonly<AuthState>;\n },\n loginWithRedirect: (options?) => client.loginWithRedirect(options),\n loginWithPopup: (options?) => client.loginWithPopup(options),\n handleRedirectCallback: (url?) => client.handleRedirectCallback(url),\n getAccessToken: (options?) => client.getAccessToken(options),\n logout: (options?) => client.logout(options),\n removeUser: () => client.removeUser(),\n install(app: App) {\n client.onStateChange((s) => Object.assign(reactiveState, s));\n app.provide(AUTH_ACTION_KEY, plugin);\n },\n };\n\n return plugin;\n}\n","/** Generate a cryptographically random string for PKCE code_verifier or state */\nexport function generateRandom(length = 64): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join('');\n}\n\n/** base64url-encode a buffer (no padding, url-safe) */\nfunction base64urlEncode(buffer: ArrayBuffer): string {\n return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\n/** Compute the PKCE code_challenge from a code_verifier using S256 */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoded = new TextEncoder().encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', encoded);\n return base64urlEncode(digest);\n}\n\n/** Decode a JWT payload without verifying the signature */\nexport function decodeJwtPayload(token: string): Record<string, unknown> {\n const parts = token.split('.');\n if (parts.length !== 3) throw new Error('Invalid JWT format');\n const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n try {\n return JSON.parse(atob(payload));\n } catch {\n throw new Error('Failed to decode JWT payload');\n }\n}\n","import { TokenSet } from \"./types\";\n\n// ── PKCE transaction store ────────────────────────────────────────────────────\n// Must survive the redirect to /authorize and back, so always uses sessionStorage.\n\nconst PKCE_KEY = \"__authaction_pkce__\";\n\ninterface PkceTransaction {\n state: string;\n codeVerifier: string;\n redirectUri: string;\n appState?: Record<string, unknown>;\n}\n\nconst ss = (): Storage | null =>\n typeof sessionStorage !== \"undefined\" ? sessionStorage : null;\n\nexport const pkceStore = {\n save(tx: PkceTransaction): void {\n ss()?.setItem(PKCE_KEY, JSON.stringify(tx));\n },\n get(): PkceTransaction | null {\n const raw = ss()?.getItem(PKCE_KEY) ?? null;\n return raw ? (JSON.parse(raw) as PkceTransaction) : null;\n },\n clear(): void {\n ss()?.removeItem(PKCE_KEY);\n },\n};\n\n// ── Token cache ───────────────────────────────────────────────────────────────\n\nconst TOKEN_KEY = \"__authaction_tokens__\";\n\ntype StorageBackend = \"memory\" | \"localstorage\" | \"sessionstorage\";\n\nexport class TokenCache {\n private memStore: TokenSet | null = null;\n private backend: StorageBackend;\n\n constructor(backend: StorageBackend = \"memory\") {\n this.backend = backend;\n }\n\n get(): TokenSet | null {\n if (this.backend === \"memory\") return this.memStore;\n const raw = this.getStore()?.getItem(TOKEN_KEY) ?? null;\n return raw ? (JSON.parse(raw) as TokenSet) : null;\n }\n\n set(tokens: TokenSet): void {\n if (this.backend === \"memory\") {\n this.memStore = tokens;\n return;\n }\n this.getStore()?.setItem(TOKEN_KEY, JSON.stringify(tokens));\n }\n\n clear(): void {\n this.memStore = null;\n if (this.backend !== \"memory\") this.getStore()?.removeItem(TOKEN_KEY);\n }\n\n private getStore(): Storage | null {\n if (this.backend === \"localstorage\") {\n return typeof localStorage !== \"undefined\" ? localStorage : null;\n }\n return ss();\n }\n}\n","import { generateRandom, generateCodeChallenge, decodeJwtPayload } from './pkce';\nimport { pkceStore, TokenCache } from './storage';\nimport {\n AuthActionClientConfig,\n AuthState,\n GetAccessTokenOptions,\n LoginOptions,\n LoginWithPopupOptions,\n LogoutOptions,\n RedirectCallbackResult,\n StateChangeCallback,\n TokenSet,\n UnsubscribeFn,\n User,\n UserProfile,\n} from './types';\n\nconst DEFAULT_SCOPE = 'openid profile email';\n// Refresh the access token 60 seconds before it expires\nconst REFRESH_BUFFER_SECONDS = 60;\n\nexport class AuthActionClient {\n private readonly cfg: Required<Pick<AuthActionClientConfig, 'domain' | 'clientId' | 'redirectUri'>> &\n AuthActionClientConfig;\n private readonly cache: TokenCache;\n private readonly listeners = new Set<StateChangeCallback>();\n\n private state: AuthState = { isAuthenticated: false, isLoading: true, user: undefined, error: undefined };\n\n constructor(config: AuthActionClientConfig) {\n if (!config.domain) throw new Error('AuthActionClient: \"domain\" is required but was not provided.');\n if (!config.clientId) throw new Error('AuthActionClient: \"clientId\" is required but was not provided.');\n if (!config.redirectUri) throw new Error('AuthActionClient: \"redirectUri\" is required but was not provided.');\n this.cfg = config as typeof this.cfg;\n this.cache = new TokenCache(config.cacheLocation ?? 'memory');\n // Restore state from cache on init (non-blocking)\n void this.loadStateFromCache();\n }\n\n // ── Login ────────────────────────────────────────────────────────────────────\n\n async loginWithRedirect(options: LoginOptions = {}): Promise<void> {\n this.setState({ ...this.state, activeNavigator: 'loginWithRedirect' });\n try {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({\n state,\n codeVerifier,\n redirectUri: this.cfg.redirectUri,\n appState: options.appState,\n });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n this.navigate(`https://${this.cfg.domain}/oauth2/authorize?${params}`);\n } catch (err) {\n this.setState({\n isAuthenticated: this.state.isAuthenticated,\n isLoading: false,\n user: this.state.user,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n throw err;\n }\n }\n\n /** Opens AuthAction login in a popup window instead of a full redirect */\n async loginWithPopup(options: LoginWithPopupOptions = {}): Promise<void> {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({ state, codeVerifier, redirectUri: this.cfg.redirectUri, appState: options.appState });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n const popup = options.popup ?? window.open(\n `https://${this.cfg.domain}/oauth2/authorize?${params}`,\n 'authaction:login',\n 'width=480,height=640,left=100,top=100',\n );\n\n if (!popup) throw new Error('Popup was blocked. Allow popups for this site and try again.');\n\n await new Promise<void>((resolve, reject) => {\n const listener = async (event: MessageEvent) => {\n if (event.origin !== window.location.origin) return;\n if (!event.data?.type?.startsWith('authaction:')) return;\n\n window.removeEventListener('message', listener);\n\n if (event.data.type === 'authaction:callback') {\n try {\n const url = new URL(event.data.url);\n await this.exchangeCodeFromUrl(url);\n resolve();\n } catch (err) {\n reject(err);\n }\n } else if (event.data.type === 'authaction:error') {\n reject(new Error(event.data.error));\n }\n };\n window.addEventListener('message', listener);\n });\n }\n\n // ── Callback ─────────────────────────────────────────────────────────────────\n\n /**\n * Call this on the redirect callback page (e.g. /callback).\n * Exchanges the authorization code for tokens and returns the original appState.\n */\n async handleRedirectCallback(url?: string): Promise<RedirectCallbackResult> {\n const callbackUrl = new URL(url ?? window.location.href);\n const appState = await this.exchangeCodeFromUrl(callbackUrl);\n\n // Clean the code/state from the URL without a page reload\n const clean = new URL(window.location.href);\n clean.searchParams.delete('code');\n clean.searchParams.delete('state');\n window.history.replaceState({}, document.title, clean.toString());\n\n return { appState };\n }\n\n /**\n * Call this from the popup callback page to relay the URL back to the opener.\n * Place this call in the script that runs on your redirectUri page when in popup mode.\n */\n static handlePopupCallback(url?: string): void {\n if (!window.opener) return;\n window.opener.postMessage(\n { type: 'authaction:callback', url: url ?? window.location.href },\n window.location.origin,\n );\n window.close();\n }\n\n // ── Auth state ────────────────────────────────────────────────────────────────\n\n async isAuthenticated(): Promise<boolean> {\n const tokens = this.cache.get();\n if (!tokens) return false;\n // Auto-refresh if near expiry\n if (this.isExpired(tokens)) {\n try {\n await this.refreshTokens();\n } catch {\n return false;\n }\n }\n return true;\n }\n\n async getUser<T extends User = User>(): Promise<T | undefined> {\n if (!(await this.isAuthenticated())) return undefined;\n const tokens = this.cache.get();\n if (!tokens?.id_token) return undefined;\n try {\n return decodeJwtPayload(tokens.id_token) as unknown as T;\n } catch {\n return undefined;\n }\n }\n\n // ── Tokens ────────────────────────────────────────────────────────────────────\n\n /**\n * Returns a valid access token, refreshing automatically if needed.\n * Use this as the Bearer token for API calls including the AuthAction Files service.\n *\n * @example\n * const token = await client.getAccessToken();\n * fetch('/api/v1/files', { headers: { Authorization: `Bearer ${token}` } });\n */\n async getAccessToken(options: GetAccessTokenOptions = {}): Promise<string> {\n let tokens = this.cache.get();\n\n if (!tokens) throw new Error('Not authenticated — call loginWithRedirect() first');\n\n if (options.forceRefresh || this.isExpired(tokens)) {\n tokens = await this.refreshTokens();\n }\n\n return tokens.access_token;\n }\n\n // ── Logout ────────────────────────────────────────────────────────────────────\n\n async logout(options: LogoutOptions = {}): Promise<void> {\n this.cache.clear();\n\n if (options.federated === false) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined, activeNavigator: 'logout' });\n\n const returnTo = options.returnTo ?? this.cfg.postLogoutRedirectUri;\n const params = new URLSearchParams({\n client_id: options.clientId ?? this.cfg.clientId,\n ...(returnTo ? { post_logout_redirect_uri: returnTo } : {}),\n });\n\n this.navigate(`https://${this.cfg.domain}/oidc/logout?${params}`);\n }\n\n /**\n * Clears the local session (tokens + state) without hitting the server's end-session endpoint.\n * Use this to handle 401 responses from APIs where the server already considers the session gone.\n */\n removeUser(): void {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n\n // ── State subscriptions ────────────────────────────────────────────────────────\n\n onStateChange(callback: StateChangeCallback): UnsubscribeFn {\n this.listeners.add(callback);\n // Emit current state immediately\n callback(this.state);\n return () => this.listeners.delete(callback);\n }\n\n getState(): AuthState {\n return { ...this.state };\n }\n\n // ── Private ───────────────────────────────────────────────────────────────────\n\n private async exchangeCodeFromUrl(url: URL): Promise<Record<string, unknown> | undefined> {\n const code = url.searchParams.get('code');\n const returnedState = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n if (error) throw new Error(errorDescription ?? error);\n if (!code) throw new Error('No authorization code in callback URL');\n\n const tx = pkceStore.get();\n pkceStore.clear();\n\n if (!tx) throw new Error('No PKCE transaction found — did the login session expire?');\n if (tx.state !== returnedState) throw new Error('State mismatch — possible CSRF attack');\n\n const tokens = await this.exchangeCode(code, tx.codeVerifier, tx.redirectUri);\n this.cache.set(tokens);\n\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(tokens), error: undefined });\n\n return tx.appState;\n }\n\n private async exchangeCode(code: string, codeVerifier: string, redirectUri: string): Promise<TokenSet> {\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.cfg.clientId,\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}));\n throw new Error(err.error_description ?? err.error ?? 'Token exchange failed');\n }\n\n const data = await res.json();\n return this.normaliseTokenResponse(data);\n }\n\n private async refreshTokens(): Promise<TokenSet> {\n const tokens = this.cache.get();\n if (!tokens?.refresh_token) throw new Error('No refresh token available');\n\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.cfg.clientId,\n refresh_token: tokens.refresh_token,\n }),\n });\n\n if (!res.ok) {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n throw new Error('Token refresh failed — user must re-authenticate');\n }\n\n const data = await res.json();\n const refreshed = this.normaliseTokenResponse(data);\n this.cache.set(refreshed);\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(refreshed), error: undefined });\n return refreshed;\n }\n\n private normaliseTokenResponse(data: Record<string, unknown>): TokenSet {\n const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : 3600;\n return {\n access_token: data.access_token as string,\n id_token: data.id_token as string | undefined,\n refresh_token: data.refresh_token as string | undefined,\n scope: data.scope as string | undefined,\n expires_at: Math.floor(Date.now() / 1000) + expiresIn,\n };\n }\n\n private isExpired(tokens: TokenSet): boolean {\n return tokens.expires_at - REFRESH_BUFFER_SECONDS < Math.floor(Date.now() / 1000);\n }\n\n private async loadStateFromCache(): Promise<void> {\n const tokens = this.cache.get();\n if (!tokens) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n try {\n if (this.isExpired(tokens)) await this.refreshTokens();\n const cached = this.cache.get();\n this.setState({ isAuthenticated: true, isLoading: false, user: cached ? this.buildUser(cached) : undefined, error: undefined });\n } catch {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n }\n\n private buildUser(tokens: TokenSet): User | undefined {\n if (!tokens.id_token) return undefined;\n try {\n const claims = decodeJwtPayload(tokens.id_token) as User;\n const user: User = { ...claims, access_token: tokens.access_token };\n const profile: UserProfile = {\n sub: user.sub,\n name: user.name,\n email: user.email,\n email_verified: user.email_verified,\n picture: user.picture,\n };\n // Copy any extra claims from the ID token into profile\n for (const key of Object.keys(user)) {\n if (!(key in profile) && key !== 'access_token' && key !== 'profile') {\n profile[key] = user[key];\n }\n }\n user.profile = profile;\n return user;\n } catch {\n return undefined;\n }\n }\n\n /** Extracted for testability — spy on this method to capture redirect URLs */\n protected navigate(url: string): void {\n window.location.assign(url);\n }\n\n private setState(next: AuthState): void {\n this.state = next;\n this.notifyListeners(next);\n }\n\n private notifyListeners(state: AuthState): void {\n this.state = state;\n this.listeners.forEach((cb) => cb(state));\n }\n}\n","import { computed, inject } from 'vue';\nimport { AUTH_ACTION_KEY } from './plugin';\nimport type { AuthActionPlugin } from './plugin';\nimport type { GetAccessTokenOptions, User } from '../types';\n\n/**\n * Primary composable — returns the full auth instance with state and all methods.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useAuthAction } from '@authaction/web-sdk/vue';\n *\n * const { state, loginWithRedirect, logout } = useAuthAction();\n * </script>\n * ```\n */\nexport function useAuthAction(): AuthActionPlugin {\n const auth = inject(AUTH_ACTION_KEY);\n if (!auth) {\n throw new Error(\n 'useAuthAction() must be called inside a component under a Vue app with the AuthAction plugin installed. ' +\n 'Call app.use(createAuthAction({ domain, clientId, redirectUri })) in main.ts.',\n );\n }\n return auth;\n}\n\n/** Reactive computed ref that is true when the user is authenticated */\nexport function useIsAuthenticated() {\n const auth = useAuthAction();\n return computed(() => auth.state.isAuthenticated);\n}\n\n/** Reactive computed ref that is true while the SDK is resolving initial auth state */\nexport function useAuthLoading() {\n const auth = useAuthAction();\n return computed(() => auth.state.isLoading);\n}\n\n/** Reactive computed ref with the current user profile, or undefined when not authenticated */\nexport function useUser<T extends User = User>() {\n const auth = useAuthAction();\n return computed(() => auth.state.user as T | undefined);\n}\n\n/**\n * Returns a function that fetches a valid access token on demand.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { useGetAccessToken } from '@authaction/web-sdk/vue';\n *\n * const getToken = useGetAccessToken();\n *\n * async function uploadFile(file: File) {\n * const token = await getToken();\n * await fetch('/api/v1/files/upload', {\n * method: 'POST',\n * headers: { Authorization: `Bearer ${token}` },\n * body: file,\n * });\n * }\n * </script>\n * ```\n */\nexport function useGetAccessToken() {\n const { getAccessToken } = useAuthAction();\n return (options?: GetAccessTokenOptions) => getAccessToken(options);\n}\n","import { watch } from 'vue';\nimport type { NavigationGuardWithThis } from 'vue-router';\nimport type { AuthActionPlugin } from './plugin';\n\n/**\n * Creates a Vue Router navigation guard that redirects unauthenticated users to login.\n * Waits for the SDK to finish initialising before checking auth state.\n *\n * @example\n * ```ts\n * // router/index.ts\n * import { createRouter } from 'vue-router';\n * import { createAuthGuard } from '@authaction/web-sdk/vue';\n * import { auth } from '../main'; // the createAuthAction() instance\n *\n * const router = createRouter({ ... });\n * router.beforeEach(createAuthGuard(auth));\n * ```\n */\nexport function createAuthGuard(auth: AuthActionPlugin): NavigationGuardWithThis<undefined> {\n return async (to) => {\n if (auth.state.isLoading) {\n await new Promise<void>((resolve) => {\n const stop = watch(\n () => auth.state.isLoading,\n (loading) => {\n if (!loading) {\n stop();\n resolve();\n }\n },\n );\n });\n }\n\n if (auth.state.isAuthenticated) return true;\n\n await auth.loginWithRedirect({ appState: { returnTo: to.fullPath } });\n return false;\n };\n}\n","/**\n * Returns true if the given URL (or window.location) contains OAuth2 callback\n * params — i.e. the authorization server has redirected back with a code or error.\n * Mirrors react-oidc-context's hasAuthParams() for drop-in compatibility.\n */\nexport function hasAuthParams(url?: string): boolean {\n const search = url ? new URL(url).search : window.location.search;\n const params = new URLSearchParams(search);\n return params.has('code') || params.has('error');\n}\n"],"mappings":"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","names":["vue_exports","__export","AUTH_ACTION_KEY","createAuthAction","createAuthGuard","hasAuthParams","useAuthAction","useAuthLoading","useGetAccessToken","useIsAuthenticated","useUser","__toCommonJS","import_vue","generateRandom","length","chars","array","byte","base64urlEncode","buffer","generateCodeChallenge","verifier","encoded","digest","decodeJwtPayload","token","parts","payload","PKCE_KEY","ss","pkceStore","tx","raw","TOKEN_KEY","TokenCache","backend","tokens","DEFAULT_SCOPE","REFRESH_BUFFER_SECONDS","AuthActionClient","config","TokenCache","options","state","generateRandom","codeVerifier","codeChallenge","generateCodeChallenge","pkceStore","params","err","resolve","reject","listener","event","url","callbackUrl","appState","clean","tokens","decodeJwtPayload","returnTo","callback","code","returnedState","error","errorDescription","tx","redirectUri","res","data","refreshed","expiresIn","cached","user","profile","key","next","cb","AUTH_ACTION_KEY","createAuthAction","config","client","AuthActionClient","reactiveState","plugin","options","url","app","s","import_vue","useAuthAction","auth","AUTH_ACTION_KEY","useIsAuthenticated","useAuthLoading","useUser","useGetAccessToken","getAccessToken","options","import_vue","createAuthGuard","auth","to","resolve","stop","loading","hasAuthParams","url","search","params"]}
@@ -1,2 +1,2 @@
1
- import{c,d as p}from"../chunk-DHV7MPBE.mjs";import{reactive as A,readonly as l}from"vue";var s=Symbol("AuthAction");function h(t){let o=new c(t),n=A(o.getState()),r={get state(){return l(n)},loginWithRedirect:e=>o.loginWithRedirect(e),loginWithPopup:e=>o.loginWithPopup(e),handleRedirectCallback:e=>o.handleRedirectCallback(e),getAccessToken:e=>o.getAccessToken(e),logout:e=>o.logout(e),removeUser:()=>o.removeUser(),install(e){o.onStateChange(a=>Object.assign(n,a)),e.provide(s,r)}};return r}import{computed as u,inject as d}from"vue";function i(){let t=d(s);if(!t)throw new Error("useAuthAction() must be called inside a component under a Vue app with the AuthAction plugin installed. Call app.use(createAuthAction({ domain, clientId, redirectUri })) in main.ts.");return t}function g(){let t=i();return u(()=>t.state.isAuthenticated)}function m(){let t=i();return u(()=>t.state.isLoading)}function f(){let t=i();return u(()=>t.state.user)}function P(){let{getAccessToken:t}=i();return o=>t(o)}import{watch as T}from"vue";function y(t){return async o=>(t.state.isLoading&&await new Promise(n=>{let r=T(()=>t.state.isLoading,e=>{e||(r(),n())})}),t.state.isAuthenticated?!0:(await t.loginWithRedirect({appState:{returnTo:o.fullPath}}),!1))}export{s as AUTH_ACTION_KEY,h as createAuthAction,y as createAuthGuard,p as hasAuthParams,i as useAuthAction,m as useAuthLoading,P as useGetAccessToken,g as useIsAuthenticated,f as useUser};
1
+ import{c,d as p}from"../chunk-WZ5VSANX.mjs";import{reactive as A,readonly as l}from"vue";var s=Symbol("AuthAction");function h(t){let o=new c(t),n=A(o.getState()),r={get state(){return l(n)},loginWithRedirect:e=>o.loginWithRedirect(e),loginWithPopup:e=>o.loginWithPopup(e),handleRedirectCallback:e=>o.handleRedirectCallback(e),getAccessToken:e=>o.getAccessToken(e),logout:e=>o.logout(e),removeUser:()=>o.removeUser(),install(e){o.onStateChange(a=>Object.assign(n,a)),e.provide(s,r)}};return r}import{computed as u,inject as d}from"vue";function i(){let t=d(s);if(!t)throw new Error("useAuthAction() must be called inside a component under a Vue app with the AuthAction plugin installed. Call app.use(createAuthAction({ domain, clientId, redirectUri })) in main.ts.");return t}function g(){let t=i();return u(()=>t.state.isAuthenticated)}function m(){let t=i();return u(()=>t.state.isLoading)}function f(){let t=i();return u(()=>t.state.user)}function P(){let{getAccessToken:t}=i();return o=>t(o)}import{watch as T}from"vue";function y(t){return async o=>(t.state.isLoading&&await new Promise(n=>{let r=T(()=>t.state.isLoading,e=>{e||(r(),n())})}),t.state.isAuthenticated?!0:(await t.loginWithRedirect({appState:{returnTo:o.fullPath}}),!1))}export{s as AUTH_ACTION_KEY,h as createAuthAction,y as createAuthGuard,p as hasAuthParams,i as useAuthAction,m as useAuthLoading,P as useGetAccessToken,g as useIsAuthenticated,f as useUser};
2
2
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,35 +1,40 @@
1
1
  {
2
2
  "name": "@authaction/web-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "AuthAction OAuth2 client SDK for web — framework agnostic, with React, Angular, Vue, and Next.js bindings",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "browser": "./dist/index.js",
10
12
  "import": "./dist/index.mjs",
11
- "require": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
13
+ "require": "./dist/index.js"
13
14
  },
14
15
  "./react": {
16
+ "types": "./dist/react/index.d.ts",
17
+ "browser": "./dist/react/index.js",
15
18
  "import": "./dist/react/index.mjs",
16
- "require": "./dist/react/index.js",
17
- "types": "./dist/react/index.d.ts"
19
+ "require": "./dist/react/index.js"
18
20
  },
19
21
  "./angular": {
22
+ "types": "./dist/angular/index.d.ts",
23
+ "browser": "./dist/angular/index.js",
20
24
  "import": "./dist/angular/index.mjs",
21
- "require": "./dist/angular/index.js",
22
- "types": "./dist/angular/index.d.ts"
25
+ "require": "./dist/angular/index.js"
23
26
  },
24
27
  "./vue": {
28
+ "types": "./dist/vue/index.d.ts",
29
+ "browser": "./dist/vue/index.js",
25
30
  "import": "./dist/vue/index.mjs",
26
- "require": "./dist/vue/index.js",
27
- "types": "./dist/vue/index.d.ts"
31
+ "require": "./dist/vue/index.js"
28
32
  },
29
33
  "./nextjs": {
34
+ "types": "./dist/nextjs/index.d.ts",
35
+ "browser": "./dist/nextjs/index.js",
30
36
  "import": "./dist/nextjs/index.mjs",
31
- "require": "./dist/nextjs/index.js",
32
- "types": "./dist/nextjs/index.d.ts"
37
+ "require": "./dist/nextjs/index.js"
33
38
  }
34
39
  },
35
40
  "peerDependencies": {
@@ -66,10 +71,18 @@
66
71
  },
67
72
  "typesVersions": {
68
73
  "*": {
69
- "react": ["dist/react/index.d.ts"],
70
- "angular": ["dist/angular/index.d.ts"],
71
- "vue": ["dist/vue/index.d.ts"],
72
- "nextjs": ["dist/nextjs/index.d.ts"]
74
+ "react": [
75
+ "dist/react/index.d.ts"
76
+ ],
77
+ "angular": [
78
+ "dist/angular/index.d.ts"
79
+ ],
80
+ "vue": [
81
+ "dist/vue/index.d.ts"
82
+ ],
83
+ "nextjs": [
84
+ "dist/nextjs/index.d.ts"
85
+ ]
73
86
  }
74
87
  },
75
88
  "files": [
@@ -1,2 +0,0 @@
1
- var P=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var C=(n,e,t,r)=>{for(var i=r>1?void 0:r?v(e,t):e,o=n.length-1,s;o>=0;o--)(s=n[o])&&(i=(r?s(e,t,i):s(i))||i);return r&&i&&P(e,t,i),i},b=(n,e)=>(t,r)=>e(t,r,n);function c(n=64){let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",t=new Uint8Array(n);return crypto.getRandomValues(t),Array.from(t,r=>e[r%e.length]).join("")}function U(n){return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function g(n){let e=new TextEncoder().encode(n),t=await crypto.subtle.digest("SHA-256",e);return U(t)}function p(n){let e=n.split(".");if(e.length!==3)throw new Error("Invalid JWT format");let t=e[1].replace(/-/g,"+").replace(/_/g,"/");try{return JSON.parse(atob(t))}catch{throw new Error("Failed to decode JWT payload")}}var m="__authaction_pkce__",l=()=>typeof sessionStorage<"u"?sessionStorage:null,d={save(n){l()?.setItem(m,JSON.stringify(n))},get(){let n=l()?.getItem(m)??null;return n?JSON.parse(n):null},clear(){l()?.removeItem(m)}},w="__authaction_tokens__",u=class{constructor(e="memory"){this.memStore=null;this.backend=e}get(){if(this.backend==="memory")return this.memStore;let e=this.getStore()?.getItem(w)??null;return e?JSON.parse(e):null}set(e){if(this.backend==="memory"){this.memStore=e;return}this.getStore()?.setItem(w,JSON.stringify(e))}clear(){this.memStore=null,this.backend!=="memory"&&this.getStore()?.removeItem(w)}getStore(){return this.backend==="localstorage"?typeof localStorage<"u"?localStorage:null:l()}};var _="openid profile email",T=60,y=class{constructor(e){this.listeners=new Set;this.state={isAuthenticated:!1,isLoading:!0,user:void 0,error:void 0};this.cfg=e,this.cache=new u(e.cacheLocation??"memory"),this.loadStateFromCache()}async loginWithRedirect(e={}){this.setState({...this.state,activeNavigator:"loginWithRedirect"});try{let t=c(32),r=c(64),i=await g(r);d.save({state:t,codeVerifier:r,redirectUri:this.cfg.redirectUri,appState:e.appState});let o=new URLSearchParams({response_type:"code",client_id:this.cfg.clientId,redirect_uri:this.cfg.redirectUri,scope:this.cfg.scope??_,state:t,code_challenge:i,code_challenge_method:"S256",...this.cfg.authorizationParams,...e.authorizationParams});this.navigate(`https://${this.cfg.domain}/oauth2/authorize?${o}`)}catch(t){throw this.setState({isAuthenticated:this.state.isAuthenticated,isLoading:!1,user:this.state.user,error:t instanceof Error?t:new Error(String(t))}),t}}async loginWithPopup(e={}){let t=c(32),r=c(64),i=await g(r);d.save({state:t,codeVerifier:r,redirectUri:this.cfg.redirectUri,appState:e.appState});let o=new URLSearchParams({response_type:"code",client_id:this.cfg.clientId,redirect_uri:this.cfg.redirectUri,scope:this.cfg.scope??_,state:t,code_challenge:i,code_challenge_method:"S256",...this.cfg.authorizationParams,...e.authorizationParams});if(!(e.popup??window.open(`https://${this.cfg.domain}/oauth2/authorize?${o}`,"authaction:login","width=480,height=640,left=100,top=100")))throw new Error("Popup was blocked. Allow popups for this site and try again.");await new Promise((h,S)=>{let k=async a=>{if(a.origin===window.location.origin&&a.data?.type?.startsWith("authaction:"))if(window.removeEventListener("message",k),a.data.type==="authaction:callback")try{let f=new URL(a.data.url);await this.exchangeCodeFromUrl(f),h()}catch(f){S(f)}else a.data.type==="authaction:error"&&S(new Error(a.data.error))};window.addEventListener("message",k)})}async handleRedirectCallback(e){let t=new URL(e??window.location.href),r=await this.exchangeCodeFromUrl(t),i=new URL(window.location.href);return i.searchParams.delete("code"),i.searchParams.delete("state"),window.history.replaceState({},document.title,i.toString()),{appState:r}}static handlePopupCallback(e){window.opener&&(window.opener.postMessage({type:"authaction:callback",url:e??window.location.href},window.location.origin),window.close())}async isAuthenticated(){let e=this.cache.get();if(!e)return!1;if(this.isExpired(e))try{await this.refreshTokens()}catch{return!1}return!0}async getUser(){if(!await this.isAuthenticated())return;let e=this.cache.get();if(e?.id_token)try{return p(e.id_token)}catch{return}}async getAccessToken(e={}){let t=this.cache.get();if(!t)throw new Error("Not authenticated \u2014 call loginWithRedirect() first");return(e.forceRefresh||this.isExpired(t))&&(t=await this.refreshTokens()),t.access_token}async logout(e={}){if(this.cache.clear(),e.federated===!1){this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0});return}this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0,activeNavigator:"logout"});let t=e.returnTo??this.cfg.postLogoutRedirectUri,r=new URLSearchParams({client_id:e.clientId??this.cfg.clientId,...t?{post_logout_redirect_uri:t}:{}});this.navigate(`https://${this.cfg.domain}/oidc/logout?${r}`)}removeUser(){this.cache.clear(),this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0})}onStateChange(e){return this.listeners.add(e),e(this.state),()=>this.listeners.delete(e)}getState(){return{...this.state}}async exchangeCodeFromUrl(e){let t=e.searchParams.get("code"),r=e.searchParams.get("state"),i=e.searchParams.get("error"),o=e.searchParams.get("error_description");if(i)throw new Error(o??i);if(!t)throw new Error("No authorization code in callback URL");let s=d.get();if(d.clear(),!s)throw new Error("No PKCE transaction found \u2014 did the login session expire?");if(s.state!==r)throw new Error("State mismatch \u2014 possible CSRF attack");let h=await this.exchangeCode(t,s.codeVerifier,s.redirectUri);return this.cache.set(h),this.setState({isAuthenticated:!0,isLoading:!1,user:this.buildUser(h),error:void 0}),s.appState}async exchangeCode(e,t,r){let i=await fetch(`https://${this.cfg.domain}/oauth2/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:this.cfg.clientId,code:e,redirect_uri:r,code_verifier:t})});if(!i.ok){let s=await i.json().catch(()=>({}));throw new Error(s.error_description??s.error??"Token exchange failed")}let o=await i.json();return this.normaliseTokenResponse(o)}async refreshTokens(){let e=this.cache.get();if(!e?.refresh_token)throw new Error("No refresh token available");let t=await fetch(`https://${this.cfg.domain}/oauth2/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",client_id:this.cfg.clientId,refresh_token:e.refresh_token})});if(!t.ok)throw this.cache.clear(),this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0}),new Error("Token refresh failed \u2014 user must re-authenticate");let r=await t.json(),i=this.normaliseTokenResponse(r);return this.cache.set(i),this.setState({isAuthenticated:!0,isLoading:!1,user:this.buildUser(i),error:void 0}),i}normaliseTokenResponse(e){let t=typeof e.expires_in=="number"?e.expires_in:3600;return{access_token:e.access_token,id_token:e.id_token,refresh_token:e.refresh_token,scope:e.scope,expires_at:Math.floor(Date.now()/1e3)+t}}isExpired(e){return e.expires_at-T<Math.floor(Date.now()/1e3)}async loadStateFromCache(){let e=this.cache.get();if(!e){this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0});return}try{this.isExpired(e)&&await this.refreshTokens();let t=this.cache.get();this.setState({isAuthenticated:!0,isLoading:!1,user:t?this.buildUser(t):void 0,error:void 0})}catch{this.setState({isAuthenticated:!1,isLoading:!1,user:void 0,error:void 0})}}buildUser(e){if(e.id_token)try{let r={...p(e.id_token),access_token:e.access_token},i={sub:r.sub,name:r.name,email:r.email,email_verified:r.email_verified,picture:r.picture};for(let o of Object.keys(r))!(o in i)&&o!=="access_token"&&o!=="profile"&&(i[o]=r[o]);return r.profile=i,r}catch{return}}navigate(e){window.location.assign(e)}setState(e){this.state=e,this.notifyListeners(e)}notifyListeners(e){this.state=e,this.listeners.forEach(t=>t(e))}};function I(n){let e=n?new URL(n).search:window.location.search,t=new URLSearchParams(e);return t.has("code")||t.has("error")}export{C as a,b,y as c,I as d};
2
- //# sourceMappingURL=chunk-DHV7MPBE.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pkce.ts","../src/storage.ts","../src/client.ts","../src/utils.ts"],"sourcesContent":["/** Generate a cryptographically random string for PKCE code_verifier or state */\nexport function generateRandom(length = 64): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => chars[byte % chars.length]).join('');\n}\n\n/** base64url-encode a buffer (no padding, url-safe) */\nfunction base64urlEncode(buffer: ArrayBuffer): string {\n return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\n/** Compute the PKCE code_challenge from a code_verifier using S256 */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoded = new TextEncoder().encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', encoded);\n return base64urlEncode(digest);\n}\n\n/** Decode a JWT payload without verifying the signature */\nexport function decodeJwtPayload(token: string): Record<string, unknown> {\n const parts = token.split('.');\n if (parts.length !== 3) throw new Error('Invalid JWT format');\n const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n try {\n return JSON.parse(atob(payload));\n } catch {\n throw new Error('Failed to decode JWT payload');\n }\n}\n","import { TokenSet } from \"./types\";\n\n// ── PKCE transaction store ────────────────────────────────────────────────────\n// Must survive the redirect to /authorize and back, so always uses sessionStorage.\n\nconst PKCE_KEY = \"__authaction_pkce__\";\n\ninterface PkceTransaction {\n state: string;\n codeVerifier: string;\n redirectUri: string;\n appState?: Record<string, unknown>;\n}\n\nconst ss = (): Storage | null =>\n typeof sessionStorage !== \"undefined\" ? sessionStorage : null;\n\nexport const pkceStore = {\n save(tx: PkceTransaction): void {\n ss()?.setItem(PKCE_KEY, JSON.stringify(tx));\n },\n get(): PkceTransaction | null {\n const raw = ss()?.getItem(PKCE_KEY) ?? null;\n return raw ? (JSON.parse(raw) as PkceTransaction) : null;\n },\n clear(): void {\n ss()?.removeItem(PKCE_KEY);\n },\n};\n\n// ── Token cache ───────────────────────────────────────────────────────────────\n\nconst TOKEN_KEY = \"__authaction_tokens__\";\n\ntype StorageBackend = \"memory\" | \"localstorage\" | \"sessionstorage\";\n\nexport class TokenCache {\n private memStore: TokenSet | null = null;\n private backend: StorageBackend;\n\n constructor(backend: StorageBackend = \"memory\") {\n this.backend = backend;\n }\n\n get(): TokenSet | null {\n if (this.backend === \"memory\") return this.memStore;\n const raw = this.getStore()?.getItem(TOKEN_KEY) ?? null;\n return raw ? (JSON.parse(raw) as TokenSet) : null;\n }\n\n set(tokens: TokenSet): void {\n if (this.backend === \"memory\") {\n this.memStore = tokens;\n return;\n }\n this.getStore()?.setItem(TOKEN_KEY, JSON.stringify(tokens));\n }\n\n clear(): void {\n this.memStore = null;\n if (this.backend !== \"memory\") this.getStore()?.removeItem(TOKEN_KEY);\n }\n\n private getStore(): Storage | null {\n if (this.backend === \"localstorage\") {\n return typeof localStorage !== \"undefined\" ? localStorage : null;\n }\n return ss();\n }\n}\n","import { generateRandom, generateCodeChallenge, decodeJwtPayload } from './pkce';\nimport { pkceStore, TokenCache } from './storage';\nimport {\n AuthActionClientConfig,\n AuthState,\n GetAccessTokenOptions,\n LoginOptions,\n LoginWithPopupOptions,\n LogoutOptions,\n RedirectCallbackResult,\n StateChangeCallback,\n TokenSet,\n UnsubscribeFn,\n User,\n UserProfile,\n} from './types';\n\nconst DEFAULT_SCOPE = 'openid profile email';\n// Refresh the access token 60 seconds before it expires\nconst REFRESH_BUFFER_SECONDS = 60;\n\nexport class AuthActionClient {\n private readonly cfg: Required<Pick<AuthActionClientConfig, 'domain' | 'clientId' | 'redirectUri'>> &\n AuthActionClientConfig;\n private readonly cache: TokenCache;\n private readonly listeners = new Set<StateChangeCallback>();\n\n private state: AuthState = { isAuthenticated: false, isLoading: true, user: undefined, error: undefined };\n\n constructor(config: AuthActionClientConfig) {\n this.cfg = config as typeof this.cfg;\n this.cache = new TokenCache(config.cacheLocation ?? 'memory');\n // Restore state from cache on init (non-blocking)\n void this.loadStateFromCache();\n }\n\n // ── Login ────────────────────────────────────────────────────────────────────\n\n async loginWithRedirect(options: LoginOptions = {}): Promise<void> {\n this.setState({ ...this.state, activeNavigator: 'loginWithRedirect' });\n try {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({\n state,\n codeVerifier,\n redirectUri: this.cfg.redirectUri,\n appState: options.appState,\n });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n this.navigate(`https://${this.cfg.domain}/oauth2/authorize?${params}`);\n } catch (err) {\n this.setState({\n isAuthenticated: this.state.isAuthenticated,\n isLoading: false,\n user: this.state.user,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n throw err;\n }\n }\n\n /** Opens AuthAction login in a popup window instead of a full redirect */\n async loginWithPopup(options: LoginWithPopupOptions = {}): Promise<void> {\n const state = generateRandom(32);\n const codeVerifier = generateRandom(64);\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n\n pkceStore.save({ state, codeVerifier, redirectUri: this.cfg.redirectUri, appState: options.appState });\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.cfg.clientId,\n redirect_uri: this.cfg.redirectUri,\n scope: this.cfg.scope ?? DEFAULT_SCOPE,\n state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n ...this.cfg.authorizationParams,\n ...options.authorizationParams,\n });\n\n const popup = options.popup ?? window.open(\n `https://${this.cfg.domain}/oauth2/authorize?${params}`,\n 'authaction:login',\n 'width=480,height=640,left=100,top=100',\n );\n\n if (!popup) throw new Error('Popup was blocked. Allow popups for this site and try again.');\n\n await new Promise<void>((resolve, reject) => {\n const listener = async (event: MessageEvent) => {\n if (event.origin !== window.location.origin) return;\n if (!event.data?.type?.startsWith('authaction:')) return;\n\n window.removeEventListener('message', listener);\n\n if (event.data.type === 'authaction:callback') {\n try {\n const url = new URL(event.data.url);\n await this.exchangeCodeFromUrl(url);\n resolve();\n } catch (err) {\n reject(err);\n }\n } else if (event.data.type === 'authaction:error') {\n reject(new Error(event.data.error));\n }\n };\n window.addEventListener('message', listener);\n });\n }\n\n // ── Callback ─────────────────────────────────────────────────────────────────\n\n /**\n * Call this on the redirect callback page (e.g. /callback).\n * Exchanges the authorization code for tokens and returns the original appState.\n */\n async handleRedirectCallback(url?: string): Promise<RedirectCallbackResult> {\n const callbackUrl = new URL(url ?? window.location.href);\n const appState = await this.exchangeCodeFromUrl(callbackUrl);\n\n // Clean the code/state from the URL without a page reload\n const clean = new URL(window.location.href);\n clean.searchParams.delete('code');\n clean.searchParams.delete('state');\n window.history.replaceState({}, document.title, clean.toString());\n\n return { appState };\n }\n\n /**\n * Call this from the popup callback page to relay the URL back to the opener.\n * Place this call in the script that runs on your redirectUri page when in popup mode.\n */\n static handlePopupCallback(url?: string): void {\n if (!window.opener) return;\n window.opener.postMessage(\n { type: 'authaction:callback', url: url ?? window.location.href },\n window.location.origin,\n );\n window.close();\n }\n\n // ── Auth state ────────────────────────────────────────────────────────────────\n\n async isAuthenticated(): Promise<boolean> {\n const tokens = this.cache.get();\n if (!tokens) return false;\n // Auto-refresh if near expiry\n if (this.isExpired(tokens)) {\n try {\n await this.refreshTokens();\n } catch {\n return false;\n }\n }\n return true;\n }\n\n async getUser<T extends User = User>(): Promise<T | undefined> {\n if (!(await this.isAuthenticated())) return undefined;\n const tokens = this.cache.get();\n if (!tokens?.id_token) return undefined;\n try {\n return decodeJwtPayload(tokens.id_token) as unknown as T;\n } catch {\n return undefined;\n }\n }\n\n // ── Tokens ────────────────────────────────────────────────────────────────────\n\n /**\n * Returns a valid access token, refreshing automatically if needed.\n * Use this as the Bearer token for API calls including the AuthAction Files service.\n *\n * @example\n * const token = await client.getAccessToken();\n * fetch('/api/v1/files', { headers: { Authorization: `Bearer ${token}` } });\n */\n async getAccessToken(options: GetAccessTokenOptions = {}): Promise<string> {\n let tokens = this.cache.get();\n\n if (!tokens) throw new Error('Not authenticated — call loginWithRedirect() first');\n\n if (options.forceRefresh || this.isExpired(tokens)) {\n tokens = await this.refreshTokens();\n }\n\n return tokens.access_token;\n }\n\n // ── Logout ────────────────────────────────────────────────────────────────────\n\n async logout(options: LogoutOptions = {}): Promise<void> {\n this.cache.clear();\n\n if (options.federated === false) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined, activeNavigator: 'logout' });\n\n const returnTo = options.returnTo ?? this.cfg.postLogoutRedirectUri;\n const params = new URLSearchParams({\n client_id: options.clientId ?? this.cfg.clientId,\n ...(returnTo ? { post_logout_redirect_uri: returnTo } : {}),\n });\n\n this.navigate(`https://${this.cfg.domain}/oidc/logout?${params}`);\n }\n\n /**\n * Clears the local session (tokens + state) without hitting the server's end-session endpoint.\n * Use this to handle 401 responses from APIs where the server already considers the session gone.\n */\n removeUser(): void {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n\n // ── State subscriptions ────────────────────────────────────────────────────────\n\n onStateChange(callback: StateChangeCallback): UnsubscribeFn {\n this.listeners.add(callback);\n // Emit current state immediately\n callback(this.state);\n return () => this.listeners.delete(callback);\n }\n\n getState(): AuthState {\n return { ...this.state };\n }\n\n // ── Private ───────────────────────────────────────────────────────────────────\n\n private async exchangeCodeFromUrl(url: URL): Promise<Record<string, unknown> | undefined> {\n const code = url.searchParams.get('code');\n const returnedState = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n if (error) throw new Error(errorDescription ?? error);\n if (!code) throw new Error('No authorization code in callback URL');\n\n const tx = pkceStore.get();\n pkceStore.clear();\n\n if (!tx) throw new Error('No PKCE transaction found — did the login session expire?');\n if (tx.state !== returnedState) throw new Error('State mismatch — possible CSRF attack');\n\n const tokens = await this.exchangeCode(code, tx.codeVerifier, tx.redirectUri);\n this.cache.set(tokens);\n\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(tokens), error: undefined });\n\n return tx.appState;\n }\n\n private async exchangeCode(code: string, codeVerifier: string, redirectUri: string): Promise<TokenSet> {\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.cfg.clientId,\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({}));\n throw new Error(err.error_description ?? err.error ?? 'Token exchange failed');\n }\n\n const data = await res.json();\n return this.normaliseTokenResponse(data);\n }\n\n private async refreshTokens(): Promise<TokenSet> {\n const tokens = this.cache.get();\n if (!tokens?.refresh_token) throw new Error('No refresh token available');\n\n const res = await fetch(`https://${this.cfg.domain}/oauth2/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.cfg.clientId,\n refresh_token: tokens.refresh_token,\n }),\n });\n\n if (!res.ok) {\n this.cache.clear();\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n throw new Error('Token refresh failed — user must re-authenticate');\n }\n\n const data = await res.json();\n const refreshed = this.normaliseTokenResponse(data);\n this.cache.set(refreshed);\n this.setState({ isAuthenticated: true, isLoading: false, user: this.buildUser(refreshed), error: undefined });\n return refreshed;\n }\n\n private normaliseTokenResponse(data: Record<string, unknown>): TokenSet {\n const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : 3600;\n return {\n access_token: data.access_token as string,\n id_token: data.id_token as string | undefined,\n refresh_token: data.refresh_token as string | undefined,\n scope: data.scope as string | undefined,\n expires_at: Math.floor(Date.now() / 1000) + expiresIn,\n };\n }\n\n private isExpired(tokens: TokenSet): boolean {\n return tokens.expires_at - REFRESH_BUFFER_SECONDS < Math.floor(Date.now() / 1000);\n }\n\n private async loadStateFromCache(): Promise<void> {\n const tokens = this.cache.get();\n if (!tokens) {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n return;\n }\n\n try {\n if (this.isExpired(tokens)) await this.refreshTokens();\n const cached = this.cache.get();\n this.setState({ isAuthenticated: true, isLoading: false, user: cached ? this.buildUser(cached) : undefined, error: undefined });\n } catch {\n this.setState({ isAuthenticated: false, isLoading: false, user: undefined, error: undefined });\n }\n }\n\n private buildUser(tokens: TokenSet): User | undefined {\n if (!tokens.id_token) return undefined;\n try {\n const claims = decodeJwtPayload(tokens.id_token) as User;\n const user: User = { ...claims, access_token: tokens.access_token };\n const profile: UserProfile = {\n sub: user.sub,\n name: user.name,\n email: user.email,\n email_verified: user.email_verified,\n picture: user.picture,\n };\n // Copy any extra claims from the ID token into profile\n for (const key of Object.keys(user)) {\n if (!(key in profile) && key !== 'access_token' && key !== 'profile') {\n profile[key] = user[key];\n }\n }\n user.profile = profile;\n return user;\n } catch {\n return undefined;\n }\n }\n\n /** Extracted for testability — spy on this method to capture redirect URLs */\n protected navigate(url: string): void {\n window.location.assign(url);\n }\n\n private setState(next: AuthState): void {\n this.state = next;\n this.notifyListeners(next);\n }\n\n private notifyListeners(state: AuthState): void {\n this.state = state;\n this.listeners.forEach((cb) => cb(state));\n }\n}\n","/**\n * Returns true if the given URL (or window.location) contains OAuth2 callback\n * params — i.e. the authorization server has redirected back with a code or error.\n * Mirrors react-oidc-context's hasAuthParams() for drop-in compatibility.\n */\nexport function hasAuthParams(url?: string): boolean {\n const search = url ? new URL(url).search : window.location.search;\n const params = new URLSearchParams(search);\n return params.has('code') || params.has('error');\n}\n"],"mappings":"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","names":["generateRandom","length","chars","array","byte","base64urlEncode","buffer","generateCodeChallenge","verifier","encoded","digest","decodeJwtPayload","token","parts","payload","PKCE_KEY","ss","pkceStore","tx","raw","TOKEN_KEY","TokenCache","backend","tokens","DEFAULT_SCOPE","REFRESH_BUFFER_SECONDS","AuthActionClient","config","TokenCache","options","state","generateRandom","codeVerifier","codeChallenge","generateCodeChallenge","pkceStore","params","err","resolve","reject","listener","event","url","callbackUrl","appState","clean","tokens","decodeJwtPayload","returnTo","callback","code","returnedState","error","errorDescription","tx","redirectUri","res","data","refreshed","expiresIn","cached","user","profile","key","next","cb","hasAuthParams","url","search","params"]}