UNPKG

@analog-tools/auth

Version:

Authentication module for AnalogJS applications

1 lines 34.6 kB
{"version":3,"file":"analog-tools-auth-angular.mjs","sources":["../../../../packages/auth-angular/src/functions/user-transformer/fromKeycloak.ts","../../../../packages/auth-angular/src/functions/user-transformer/fromAuth0.ts","../../../../packages/auth-angular/src/functions/user-transformer/detectProvider.ts","../../../../packages/auth-angular/src/functions/utils/get-request-headers.ts","../../../../packages/auth-angular/src/auth.service.ts","../../../../packages/auth-angular/src/auth.provider.ts","../../../../packages/auth-angular/src/auth.guard.ts","../../../../packages/auth-angular/src/functions/login.ts","../../../../packages/auth-angular/src/functions/utils/merge-request.ts","../../../../packages/auth-angular/src/auth.interceptor.ts","../../../../packages/auth-angular/src/trpc/functions/createProxy.ts","../../../../packages/auth-angular/src/trpc/functions/createDefaultConfirmation.ts","../../../../packages/auth-angular/src/trpc/functions/wrapTrpcClientWithErrorHandling.ts","../../../../packages/auth-angular/src/trpc/trpc.injector.ts","../../../../packages/auth-angular/src/analog-tools-auth-angular.ts"],"sourcesContent":["import { AuthUser } from \"../../auth.service\";\n\nexport type KeycloakUserInfo = {\n // Core Identity Properties\n sub: string; // Subject identifier (unique user ID)\n preferred_username: string; // Username\n name: string; // Full name\n given_name: string; // First name\n family_name: string; // Last name\n email: string; // Email address\n email_verified: boolean; // Whether email has been verified\n \n // Access Control Properties\n realm_access: {\n roles: string[] // Realm-level roles assigned to user\n };\n resource_access: { // Client-specific roles\n [clientId: string]: {\n roles: string[]\n }\n };\n \n // Additional Metadata\n groups: string[]; // Groups the user belongs to\n scope: string; // OAuth scopes granted\n sid: string; // Session ID\n acr: string; // Authentication context class reference\n iat: number; // Issued at timestamp\n exp: number; // Expiration timestamp\n auth_time: number; // Time when authentication occurred\n}\n\n\nexport function fromKeycloak (keycloakUser: KeycloakUserInfo): AuthUser {\n return {\n username: keycloakUser.preferred_username,\n fullName: keycloakUser.name,\n givenName: keycloakUser.given_name,\n familyName: keycloakUser.family_name,\n picture: undefined,\n email: keycloakUser.email,\n emailVerified: keycloakUser.email_verified,\n locale: undefined, // Locale is not provided in Keycloak user info\n lastLogin: new Date().toISOString(), // Assuming last login is now\n updatedAt: undefined, // Assuming updated at is now\n createdAt: undefined, // Assuming created at is now\n auth_id: keycloakUser.sub, // Using sub as auth_id\n };\n}","import { AuthUser } from \"../../auth.service\";\n\nexport type Auth0UserInfo = {\n // Core Identity Properties\n sub: string; // Subject identifier (unique user ID)\n nickname: string; // User nickname\n name: string; // Full name\n given_name?: string; // First name\n family_name?: string; // Last name\n email?: string; // Email address\n email_verified?: boolean; // Whether email has been verified\n picture?: string; // URL to user's profile picture\n locale?: string; // User's locale\n \n // Auth0 Specific Properties\n updated_at?: string; // Last update timestamp\n created_at?: string; // Creation timestamp\n last_login?: string; // Last login timestamp\n \n // Access Control Properties\n roles?: string[]; // User roles (if using Auth0 RBAC)\n permissions?: string[]; // User permissions (if using Auth0 RBAC)\n \n // Additional Metadata\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user_metadata?: Record<string, any>; // User editable metadata\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n app_metadata?: Record<string, any>; // Application metadata (controlled by apps/APIs)\n \n // Standard OIDC properties\n iss?: string; // Issuer\n aud?: string; // Audience\n iat?: number; // Issued at timestamp\n exp?: number; // Expiration timestamp\n}\n\n/**\n * Transforms an Auth0 user object into the application's AuthUser format\n * @param auth0User - The user object from Auth0\n * @returns A standardized AuthUser object\n */\nexport function fromAuth0(auth0User: Auth0UserInfo): AuthUser {\n return {\n username: auth0User.nickname || auth0User.email || '',\n fullName: auth0User.name || '',\n givenName: auth0User.given_name || '',\n familyName: auth0User.family_name || '',\n picture: auth0User.picture,\n email: auth0User.email,\n emailVerified: auth0User.email_verified,\n locale: auth0User.locale,\n lastLogin: auth0User.last_login,\n updatedAt: auth0User.updated_at,\n createdAt: auth0User.created_at,\n auth_id: auth0User.sub,\n // If roles are stored directly or in app_metadata\n roles: auth0User.roles || auth0User.app_metadata?.[\"roles\"],\n };\n}\n","import { AuthUser } from '../../auth.service';\nimport { Auth0UserInfo, fromAuth0 } from './fromAuth0';\nimport { fromKeycloak, KeycloakUserInfo } from './fromKeycloak';\n\n/**\n * Provider type for identity providers\n */\nexport type IdentityProvider = 'keycloak' | 'auth0' | 'unknown';\n\n/**\n * Generic user info type that can represent data from any provider\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type GenericUserInfo = Record<string, any>;\n\n/**\n * Detects the identity provider based on user data structure\n * @param userInfo - User information object from the provider\n * @returns The detected identity provider type\n */\nexport function detectProvider(userInfo: GenericUserInfo): IdentityProvider {\n if (!userInfo) {\n return 'unknown';\n }\n\n // Check for Keycloak-specific properties\n if (userInfo['realm_access'] || userInfo['resource_access']) {\n return 'keycloak';\n }\n\n // Check for Auth0-specific properties\n if (\n userInfo['nickname'] !== undefined ||\n userInfo['user_metadata'] !== undefined ||\n userInfo['app_metadata'] !== undefined\n ) {\n return 'auth0';\n }\n\n // If we can't determine the provider, check for common patterns\n // Auth0 typically includes an issuer URL with \"auth0.com\"\n if (\n userInfo['iss'] &&\n typeof userInfo['iss'] === 'string' &&\n userInfo['iss'].includes('auth0.com')\n ) {\n return 'auth0';\n }\n\n // Keycloak typically includes an issuer URL with \"auth/realms\"\n if (\n userInfo['iss'] &&\n typeof userInfo['iss'] === 'string' &&\n userInfo['iss'].includes('/auth/realms')\n ) {\n return 'keycloak';\n }\n\n // If we still can't determine, return unknown\n return 'unknown';\n}\n\n/**\n * Transforms user data from any supported identity provider into the application's AuthUser format\n * @param userInfo - User information object from the provider\n * @returns A standardized AuthUser object\n */\nexport function transformUserFromProvider(userInfo: GenericUserInfo): AuthUser {\n const provider = detectProvider(userInfo);\n\n switch (provider) {\n case 'keycloak':\n return fromKeycloak(userInfo as KeycloakUserInfo);\n case 'auth0':\n return fromAuth0(userInfo as Auth0UserInfo);\n case 'unknown':\n default:\n // Fallback transformation for unknown providers\n // This provides a basic mapping that should work with most standard OIDC providers\n return {\n username:\n userInfo['preferred_username'] ||\n userInfo['nickname'] ||\n userInfo['email'] ||\n userInfo['sub'] ||\n '',\n fullName: userInfo['name'] || '',\n givenName: userInfo['given_name'] || '',\n familyName: userInfo['family_name'] || '',\n picture: userInfo['picture'],\n email: userInfo['email'],\n emailVerified: userInfo['email_verified'],\n locale: userInfo['locale'],\n lastLogin: userInfo['last_login'] || new Date().toISOString(),\n updatedAt: userInfo['updated_at'],\n createdAt: userInfo['created_at'],\n auth_id: userInfo['sub'],\n roles: userInfo['roles'] || [],\n };\n }\n}\n","import { HttpHeaders } from '@angular/common/http';\nimport { ServerRequest } from '@analogjs/router/tokens';\n\nexport function getRequestHeaders(\n serverRequest: ServerRequest | null,\n originalHeaderValues?: { [key: string]: string | null | undefined }\n) {\n let headers = new HttpHeaders();\n headers = headers.set('fetch', 'true');\n\n if (originalHeaderValues) {\n Object.entries(originalHeaderValues).forEach(([key, value]) => {\n if (value !== null && value !== undefined) {\n headers = headers.set(key, value);\n }\n });\n }\n\n if (serverRequest) {\n Object.entries(serverRequest.headers).forEach(([key, value]) => {\n if (value !== null && value !== undefined && typeof value === 'string') {\n headers = headers.set(key, value);\n }\n });\n }\n return headers;\n}\n","import {\n DOCUMENT,\n effect,\n inject,\n Injectable,\n OnDestroy,\n PLATFORM_ID,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport { isPlatformBrowser } from '@angular/common';\nimport { httpResource } from '@angular/common/http';\nimport {\n GenericUserInfo,\n transformUserFromProvider,\n} from './functions/user-transformer';\nimport { getRequestHeaders } from './functions/utils/get-request-headers';\nimport { injectRequest } from '@analogjs/router/tokens';\n\nexport interface AuthUser {\n username: string;\n fullName: string;\n givenName: string;\n familyName: string;\n picture?: string;\n email?: string;\n emailVerified?: boolean;\n locale?: string;\n lastLogin?: string;\n updatedAt?: string;\n createdAt?: string;\n auth_id?: string;\n roles?: string[];\n}\n\n/**\n * Auth service for BFF (Backend for Frontend) authentication pattern\n * Uses server-side sessions with Auth0 instead of client-side tokens\n */\n@Injectable()\nexport class AuthService implements OnDestroy {\n private router = inject(Router);\n private platformId = inject(PLATFORM_ID);\n private document = inject(DOCUMENT);\n private httpRequest = injectRequest();\n private checkAuthInterval: ReturnType<typeof setInterval> | null = null;\n\n // Auth state - order matters: isAuthenticatedResource and isAuthenticated must be defined first\n readonly isAuthenticatedResource = httpResource<boolean>(\n () => ({\n url: '/api/auth/authenticated',\n method: 'GET',\n headers: getRequestHeaders(this.httpRequest, {\n accept: 'application/json',\n }),\n withCredentials: true,\n }),\n {\n defaultValue: false,\n parse: (value: unknown) => {\n return (value as { authenticated: boolean }).authenticated;\n },\n }\n );\n\n readonly isAuthenticated = this.isAuthenticatedResource.asReadonly().value;\n\n readonly userResource = httpResource<AuthUser | null>(\n () => {\n if (this.isAuthenticated()) {\n return {\n url: '/api/auth/user',\n method: 'GET',\n headers: getRequestHeaders(this.httpRequest, {\n accept: 'application/json',\n }),\n withCredentials: true,\n };\n }\n return;\n },\n {\n defaultValue: null,\n parse: (raw: unknown) => {\n return transformUserFromProvider(raw as GenericUserInfo);\n },\n }\n );\n\n readonly user = this.userResource.asReadonly().value;\n\n constructor() {\n // Check authentication status on startup\n this.isAuthenticatedResource.reload();\n\n if (isPlatformBrowser(this.platformId)) {\n // Set up periodic check for authentication status\n this.checkAuthInterval = setInterval(() => {\n this.isAuthenticatedResource.reload();\n }, 5 * 60 * 1000); // Check every 5 minutes\n }\n\n effect(() => {\n // Automatically fetch user profile when authenticated\n if (this.isAuthenticated()) {\n this.userResource.reload();\n }\n });\n }\n\n ngOnDestroy(): void {\n if (this.checkAuthInterval) {\n clearInterval(this.checkAuthInterval);\n }\n }\n\n /**\n * Login the user by redirecting to the login endpoint\n * @param targetUrl Optional URL to redirect to after login\n */\n login(targetUrl?: string): void {\n if (isPlatformBrowser(this.platformId)) {\n const redirectUri = targetUrl || this.router.url;\n const url = this.document.location.origin + redirectUri;\n this.document.location.href = `/api/auth/login?redirect_uri=${encodeURIComponent(\n url\n )}`;\n }\n }\n\n /**\n * Logout the user by redirecting to the logout endpoint\n */\n logout(): void {\n if (isPlatformBrowser(this.platformId)) {\n try {\n const logoutUrl = `/api/auth/logout?redirect_uri=${encodeURIComponent(\n '/'\n )}`;\n // Clear local state before redirect\n this.userResource.set(null);\n if (this.checkAuthInterval) {\n clearInterval(this.checkAuthInterval);\n }\n this.document.location.href = logoutUrl;\n } catch (error) {\n console.error('Logout failed:', error);\n // Implement fallback logout mechanism\n }\n }\n }\n\n /**\n * Check if user has the required roles\n * @param roles Array of roles to check\n */\n hasRoles(roles: string[]): boolean {\n const user = this.userResource.value();\n if (!user || !user.roles) return false;\n\n return roles.some((role) => user.roles?.lastIndexOf(role) !== -1);\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { AuthService } from './auth.service';\n\nexport function provideAuthClient(): EnvironmentProviders {\n return makeEnvironmentProviders([AuthService]);\n}\n","import { CanActivateFn, Router } from '@angular/router';\nimport { inject } from '@angular/core';\nimport { AuthService } from './auth.service';\n\n/**\n * Auth guard that checks if the user is authenticated\n */\nexport const authGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n\n if (authService.isAuthenticated()) {\n // User is authenticated, allow access\n return true;\n } else {\n // User is not authenticated, redirect to login\n authService.login(state.url);\n return false;\n }\n};\n\n/**\n * Role-based guard that checks if the user has the required roles\n */\nexport const roleGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n const router = inject(Router);\n\n // Get required roles from route data\n const requiredRoles = route.data?.['roles'] as string[] | undefined;\n\n if (!requiredRoles || requiredRoles.length === 0) {\n // No specific roles required\n return true;\n }\n\n if (!authService.isAuthenticated()) {\n authService.login(state.url);\n return false;\n }\n\n // Check if user has any of the required roles\n if (authService.hasRoles(requiredRoles)) {\n return true;\n }\n\n // User doesn't have required roles, redirect to access denied\n router.navigate(['/access-denied']);\n return false;\n};\n","export function redirect(uri: string) {\n document.location.href = uri;\n}\n\nexport function login(redirectUri?: string) {\n const url = document.location.origin + (redirectUri || '');\n redirect(`/api/auth/login?redirect_uri=${encodeURIComponent(url)}`);\n}\n","import { HttpHeaders, HttpRequest } from '@angular/common/http';\nimport { ServerRequest } from '@analogjs/router/tokens';\n\nexport function mergeRequest(\n originalRequest: HttpRequest<unknown>,\n serverRequest: ServerRequest | null\n) {\n let modifiedReq;\n\n if (serverRequest) {\n let headers = new HttpHeaders();\n Object.entries(serverRequest.headers).forEach(([key, value]) => {\n if (value !== null && value !== undefined && typeof value === 'string') {\n headers = headers.set(key, value);\n }\n });\n headers = headers.set('fetch', 'true');\n\n modifiedReq = originalRequest.clone({\n headers: headers,\n withCredentials: true,\n });\n } else {\n modifiedReq = originalRequest.clone({\n headers: originalRequest.headers.set('fetch', 'true'),\n withCredentials: true,\n });\n }\n\n return modifiedReq;\n}\n","import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';\nimport { catchError, EMPTY } from 'rxjs';\nimport { login } from './functions/login';\nimport { injectRequest } from '@analogjs/router/tokens';\nimport { mergeRequest } from './functions/utils/merge-request';\n\n/**\n * HTTP interceptor that:\n * 1. Adds a fetch=true header to indicate fresh data requests\n * 2. Redirects to login page when an API returns a 401 Unauthorized response\n *\n * This handles cases where a session has expired on the server-side.\n */\nexport const authInterceptor: HttpInterceptorFn = (req, next) => {\n // Skip interception for auth endpoints to avoid circular issues\n if (\n req.url.includes('/api/auth/callback') ||\n req.url.includes('/api/auth/login')\n ) {\n return next(req);\n }\n\n // Clone the request and add the fetch=true header\n const request = injectRequest();\n\n const modifiedReq = mergeRequest(req, request);\n // Use the modified request with the added header\n return next(modifiedReq).pipe(\n catchError((error: unknown) => {\n // Only handle HttpErrorResponse with 401 status\n if (error instanceof HttpErrorResponse && error.status === 401) {\n // Get current URL to redirect back after login\n const currentUrl = window.location.pathname + window.location.search;\n\n // Redirect to login page with the current URL as redirect target\n login(currentUrl);\n\n // Return empty observable to prevent the error from propagating\n return EMPTY;\n }\n\n // For other errors, rethrow\n throw error;\n })\n );\n};\n\n/**\n * Provider for the auth interceptor\n */\nexport const provideAuthInterceptor = () => ({\n provide: 'HTTP_INTERCEPTORS',\n useValue: authInterceptor,\n multi: true,\n});\n","import { Observable, catchError, throwError } from \"rxjs\";\nimport { ProcedureMethod, TRPCErrorData } from \"../types/trpc\";\nimport { TRPCClientError } from '@trpc/client';\nimport { AnyRouter } from '@trpc/server';\n\nexport function proxyClient<Router extends AnyRouter>(\n client: Record<string, unknown>,\n errorHandler: (errorData: TRPCErrorData | undefined) => boolean,\n) {\n return new Proxy(client, {\n get(target, prop) {\n return new Proxy(\n target[prop as keyof typeof target] as Record<string, unknown>,\n {\n get(target, prop) {\n return proxyProcedure<Router>(\n target[prop as keyof typeof target] as Record<string, unknown>,\n errorHandler,\n );\n },\n },\n );\n },\n });\n}\n\nfunction proxyProcedure<Router extends AnyRouter>(\n procedure: Record<string, unknown>,\n errorHandler: (errorData: TRPCErrorData | undefined) => boolean,\n) {\n return new Proxy(procedure, {\n get(procedureTarget, procedureProp) {\n const procedureMethod =\n procedureTarget[procedureProp as keyof typeof procedureTarget];\n\n // Only intercept query and mutate methods\n if (procedureProp !== 'query' && procedureProp !== 'mutate') {\n return procedureMethod;\n }\n\n // Return a wrapped version of the method that catches errors\n return function (...args: unknown[]) {\n const method = procedureMethod as ProcedureMethod;\n const result = method(...args);\n\n // If the result is an Observable (for Angular), add error handling\n if (result instanceof Observable) {\n return result.pipe(\n catchError((error) => {\n // Check if it's a TRPC client error with UNAUTHORIZED code\n if (error instanceof TRPCClientError) {\n const trpcError = error as TRPCClientError<Router>;\n const errorData = trpcError.data as TRPCErrorData | undefined;\n\n if(errorHandler(errorData)) {\n // Handle the error and prevent it from propagating\n return new Observable<never>((subscriber) => {\n subscriber.complete();\n });\n }\n }\n\n // Always rethrow the error for other error handlers\n return throwError(() => error);\n }),\n );\n }\n\n return result;\n };\n },\n });\n}","import { TRPCErrorData } from '../types/trpc';\n\nfunction confirmDialog(msg:string) {\n return new Promise(function (resolve, reject) {\n try {\n if (!window?.confirm) {\n console.error(\"confirm is not available\");\n return reject(false);\n }\n const confirmed = confirm(msg);\n\n return confirmed ? resolve(true) : reject(false);\n } catch {\n return reject(\"Error showing confirmation dialog\");\n }\n });\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function createDefaultConfirmation(_: TRPCErrorData | undefined): boolean {\n confirmDialog(\"Session expired. Do you want to refresh the page?\").then(() => {\n window.location.href = '/';\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n }).catch(() => {});\n return true;\n}\n","import { TRPCErrorData } from \"../types/trpc\";\nimport { proxyClient } from \"./createProxy\";\nimport { createDefaultConfirmation } from './createDefaultConfirmation';\n\n/**\n * Wraps a TRPC client with error handling for auth errors\n * @param client The original TRPC client\n * @param errorHandler A function to handle errors. if returns true, the error is handled and catched\n * @returns A wrapped TRPC client with error handling\n */\nexport function wrapTrpcClientWithErrorHandling<T>(\n client: Record<string, unknown>,\n errorHandler?: (errorData: TRPCErrorData | undefined) => boolean,\n): T {\n // Create a proxy that intercepts all client calls\n return proxyClient(\n client,\n errorHandler ?? createDefaultConfirmation,\n ) as unknown as T;\n}\n","import { ServerRequest } from '@analogjs/router/tokens';\nimport { wrapTrpcClientWithErrorHandling } from './functions/wrapTrpcClientWithErrorHandling';\nimport { HTTPHeaders } from '@trpc/client';\nimport { WritableSignal } from '@angular/core';\n\nexport function createTrpcClientWithAuth<T>(\n trpcClient: T,\n request: ServerRequest | null,\n TrpcHeaders: WritableSignal<HTTPHeaders>\n) {\n // Add request headers including cookies for auth\n TrpcHeaders.update((headers) => ({\n ...headers,\n fetch: 'true',\n cookie: request?.headers.cookie,\n }));\n\n // Wrap the client to add error handling\n return wrapTrpcClientWithErrorHandling<typeof trpcClient>(\n trpcClient as Record<string, unknown>\n );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}