@civic/auth 0.0.1-beta.20 → 0.0.1-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/{chunk-CBQ3HKRV.mjs → chunk-4PLCDPEN.mjs} +3 -3
  2. package/dist/chunk-4PLCDPEN.mjs.map +1 -0
  3. package/dist/chunk-5UQQYXCX.js.map +1 -1
  4. package/dist/{chunk-O6DPCPRH.js → chunk-6RFRDWIP.js} +16 -16
  5. package/dist/chunk-6RFRDWIP.js.map +1 -0
  6. package/dist/{chunk-O2SODTR3.js → chunk-7K3QN2AT.js} +3 -3
  7. package/dist/chunk-7K3QN2AT.js.map +1 -0
  8. package/dist/{chunk-HTTTZ2BP.mjs → chunk-AP4627CS.mjs} +6 -6
  9. package/dist/chunk-AP4627CS.mjs.map +1 -0
  10. package/dist/chunk-CRTRMMJ7.js.map +1 -1
  11. package/dist/{chunk-DJFTZS4P.js → chunk-CTVJJBBA.js} +7 -7
  12. package/dist/chunk-CTVJJBBA.js.map +1 -0
  13. package/dist/{chunk-VJVRFKDH.js → chunk-FHRZSX3C.js} +21 -21
  14. package/dist/chunk-FHRZSX3C.js.map +1 -0
  15. package/dist/{chunk-CZ3AVCKD.js → chunk-JDZPCA3P.js} +9 -7
  16. package/dist/chunk-JDZPCA3P.js.map +1 -0
  17. package/dist/{chunk-BFESCRFK.mjs → chunk-MK7557NR.mjs} +3 -3
  18. package/dist/chunk-MK7557NR.mjs.map +1 -0
  19. package/dist/{chunk-UADVRCHY.mjs → chunk-NLRREFOX.mjs} +4 -4
  20. package/dist/chunk-NLRREFOX.mjs.map +1 -0
  21. package/dist/{chunk-X3FQBE22.mjs → chunk-O3WGNLRO.mjs} +8 -6
  22. package/dist/chunk-O3WGNLRO.mjs.map +1 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/nextjs/client.js +11 -11
  25. package/dist/nextjs/client.js.map +1 -1
  26. package/dist/nextjs/client.mjs +5 -5
  27. package/dist/nextjs.js +31 -31
  28. package/dist/nextjs.js.map +1 -1
  29. package/dist/nextjs.mjs +4 -4
  30. package/dist/react.js +13 -13
  31. package/dist/react.js.map +1 -1
  32. package/dist/react.mjs +3 -3
  33. package/dist/server.js +3 -3
  34. package/dist/server.js.map +1 -1
  35. package/dist/server.mjs +2 -2
  36. package/package.json +3 -3
  37. package/dist/chunk-BFESCRFK.mjs.map +0 -1
  38. package/dist/chunk-CBQ3HKRV.mjs.map +0 -1
  39. package/dist/chunk-CZ3AVCKD.js.map +0 -1
  40. package/dist/chunk-DJFTZS4P.js.map +0 -1
  41. package/dist/chunk-HTTTZ2BP.mjs.map +0 -1
  42. package/dist/chunk-O2SODTR3.js.map +0 -1
  43. package/dist/chunk-O6DPCPRH.js.map +0 -1
  44. package/dist/chunk-UADVRCHY.mjs.map +0 -1
  45. package/dist/chunk-VJVRFKDH.js.map +0 -1
  46. package/dist/chunk-X3FQBE22.mjs.map +0 -1
@@ -256,7 +256,7 @@ var DEFAULT_SCOPES = [
256
256
  "offline_access"
257
257
  ];
258
258
  var IFRAME_ID = "civic-auth-iframe";
259
- var AUTH_SERVER = "https://auth-dev.civic.com/oauth";
259
+ var DEFAULT_AUTH_SERVER = "https://auth.civic.com/oauth";
260
260
  var DEFAULT_OAUTH_GET_PARAMS = ["code", "state", "iss"];
261
261
  var TOKEN_EXCHANGE_TRIGGER_TEXT = "sameDomainCodeExchangeRequired";
262
262
  var TOKEN_EXCHANGE_SUCCESS_TEXT = "serverSideTokenExchangeSuccess";
@@ -573,7 +573,7 @@ export {
573
573
  GenericUserSession,
574
574
  DEFAULT_SCOPES,
575
575
  IFRAME_ID,
576
- AUTH_SERVER,
576
+ DEFAULT_AUTH_SERVER,
577
577
  TOKEN_EXCHANGE_TRIGGER_TEXT,
578
578
  TOKEN_EXCHANGE_SUCCESS_TEXT,
579
579
  isWindowInIframe,
@@ -596,4 +596,4 @@ export {
596
596
  BrowserAuthenticationService,
597
597
  getUser
598
598
  };
599
- //# sourceMappingURL=chunk-CBQ3HKRV.mjs.map
599
+ //# sourceMappingURL=chunk-4PLCDPEN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/types.ts","../src/shared/util.ts","../src/lib/oauth.ts","../src/utils.ts","../src/lib/jwt.ts","../src/shared/UserSession.ts","../src/shared/session.ts","../src/constants.ts","../src/browser/storage.ts","../src/services/PKCE.ts","../src/services/AuthenticationService.ts","../src/services/types.ts","../src/lib/windowUtil.ts","../src/lib/postMessage.ts"],"sourcesContent":["export enum OAuthTokens {\n ID_TOKEN = \"id_token\",\n ACCESS_TOKEN = \"access_token\",\n REFRESH_TOKEN = \"refresh_token\",\n}\n\nexport enum CodeVerifier {\n COOKIE_NAME = \"code_verifier\",\n}\nexport enum UserStorage {\n USER = \"user\",\n}\nexport interface CookieConfig {\n secure?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n domain?: string;\n path?: string;\n maxAge?: number;\n httpOnly?: boolean;\n}\n\nexport type TokensCookieConfig = Record<\n OAuthTokens | CodeVerifier,\n CookieConfig\n>;\n","// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\n\nimport {\n AuthStorage,\n Endpoints,\n JWTPayload,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport { CodeVerifier, OAuthTokens } from \"./types\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { getIssuerVariations, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport * as jose from \"jose\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"./UserSession\";\n\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n) {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n const challenge = await config.pkceConsumer.getCodeChallenge();\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n console.log(\"Generated OAuth URL\", oAuthUrl.toString());\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n // TODO\n return new URL(\"http://localhost\");\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer,\n oauth2Client: OAuth2Client,\n oauthServer: string,\n endpoints: Endpoints,\n) {\n const codeVerifier = await pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in state\");\n\n const tokens =\n await oauth2Client.validateAuthorizationCode<OIDCTokenResponseBody>(code, {\n codeVerifier,\n });\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(tokens, endpoints, oauth2Client, oauthServer);\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n\n return tokens;\n}\n\nexport function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // store tokens in storage ( TODO we should probably store them against the state to allow multiple logins )\n storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);\n storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);\n if (tokens.refresh_token)\n storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);\n}\n\nexport function clearTokens(storage: AuthStorage) {\n Object.values(OAuthTokens).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n Object.values(CodeVerifier.COOKIE_NAME).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n}\nexport function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n userSession.set(null);\n}\n\nexport function retrieveTokens(\n storage: AuthStorage,\n): OIDCTokenResponseBody | null {\n const idToken = storage.get(OAuthTokens.ID_TOKEN);\n const accessToken = storage.get(OAuthTokens.ACCESS_TOKEN);\n const refreshToken = storage.get(OAuthTokens.REFRESH_TOKEN);\n\n if (!idToken || !accessToken) return null;\n\n return {\n id_token: idToken,\n access_token: accessToken,\n refresh_token: refreshToken ?? undefined,\n };\n}\n\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n endpoints: Endpoints,\n oauth2Client: OAuth2Client,\n issuer: string,\n): Promise<ParsedTokens> {\n const JWKS = jose.createRemoteJWKSet(new URL(endpoints.jwks));\n\n // validate the ID token\n const idTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.id_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n audience: oauth2Client.clientId,\n },\n );\n\n // validate the access token\n const accessTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.access_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n },\n );\n\n return withoutUndefined({\n id_token: idTokenResponse.payload,\n access_token: accessTokenResponse.payload,\n refresh_token: tokens.refresh_token,\n });\n}\n","import { DisplayMode, Endpoints, OpenIdConfiguration } from \"@/types\";\nimport { v4 as uuid } from \"uuid\";\n\nconst getIssuerVariations = (issuer: string): string[] => {\n const issuerWithoutSlash = issuer.endsWith(\"/\")\n ? issuer.slice(0, issuer.length - 1)\n : issuer;\n\n const issuerWithSlash = `${issuerWithoutSlash}/`;\n\n return [issuerWithoutSlash, issuerWithSlash];\n};\n\nconst addSlashIfNeeded = (url: string): string =>\n url.endsWith(\"/\") ? url : `${url}/`;\n\nconst getOauthEndpoints = async (oauthServer: string): Promise<Endpoints> => {\n const openIdConfigResponse = await fetch(\n `${addSlashIfNeeded(oauthServer)}.well-known/openid-configuration`,\n );\n const openIdConfig =\n (await openIdConfigResponse.json()) as OpenIdConfiguration;\n return {\n jwks: openIdConfig.jwks_uri,\n auth: openIdConfig.authorization_endpoint,\n token: openIdConfig.token_endpoint,\n userinfo: openIdConfig.userinfo_endpoint,\n };\n};\n\n/**\n * creates a state string for the OAuth2 flow, encoding the display mode too for future use\n * @param {DisplayMode} displayMode\n * @returns {string}\n */\nconst generateState = (\n displayMode: DisplayMode,\n serverTokenExchange?: boolean,\n): string => {\n const jsonString = JSON.stringify({\n uuid: uuid(),\n displayMode,\n ...(serverTokenExchange ? { serverTokenExchange } : {}),\n });\n return btoa(jsonString);\n};\n\n/**\n * parses the state string from the OAuth2 flow, decoding the display mode too\n * @param state\n * @param sessionDisplayMode\n * @returns { uuid: string, displayMode: DisplayMode }\n */\nconst displayModeFromState = (\n state: string,\n sessionDisplayMode: DisplayMode | undefined,\n): DisplayMode | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).displayMode;\n } catch {\n console.error(\"Failed to parse displayMode from state:\", state);\n return sessionDisplayMode;\n }\n};\n\nconst serverTokenExchangeFromState = (state: string): boolean | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).serverTokenExchange;\n } catch {\n console.error(\"Failed to parse serverTokenExchange from state:\", state);\n return undefined;\n }\n};\n\nexport {\n serverTokenExchangeFromState,\n getIssuerVariations,\n getOauthEndpoints,\n displayModeFromState,\n generateState,\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Checks if a popup window is blocked by the browser.\n *\n * This function attempts to open a small popup window and then checks if it was successfully created.\n * If the popup is blocked by the browser, the function returns `true`. Otherwise, it returns `false`.\n *\n * @returns {boolean} - `true` if the popup is blocked, `false` otherwise.\n */\nconst isPopupBlocked = (): boolean => {\n // First we try to open a small popup window. It either returns a window object or null.\n const popup = window.open(\"\", \"\", \"width=1,height=1\");\n\n // If window.open() returns null, popup is definitely blocked\n if (!popup) {\n return true;\n }\n\n try {\n // Try to access a property of the popup to check if it's usable\n if (typeof popup.closed === \"undefined\") {\n throw new Error(\"Popup is blocked\");\n }\n } catch {\n // Accessing the popup's properties throws an error if the popup is blocked\n return true;\n }\n\n // Close the popup immediately if it was opened\n popup.close();\n return false;\n};\n\nconst cn = (...inputs: ClassValue[]) => {\n return twMerge(clsx(inputs));\n};\n\n// This type narrows T as far as it can by:\n// - removing all keys where the value is `undefined`\n// - making keys that are not undefined required\n// So, for example: given { a: string | undefined, b: string | undefined },\n// if you pass in { a: \"foo\" }, it returns an object of type: { a: string }\ntype WithoutUndefined<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K];\n};\nexport const withoutUndefined = <T extends { [K in keyof T]: unknown }>(\n obj: T,\n): WithoutUndefined<T> => {\n const result = {} as WithoutUndefined<T>;\n\n for (const key in obj) {\n if (obj[key] !== undefined) {\n // TypeScript needs assurance that key is a valid key in WithoutUndefined<T>\n // We use type assertion here\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (result as any)[key] = obj[key];\n }\n }\n\n return result;\n};\n\nexport { cn, isPopupBlocked };\n","import { ForwardedTokens, ForwardedTokensJWT } from \"@/types.js\";\n\nexport const convertForwardedTokenFormat = (\n inputTokens: ForwardedTokensJWT,\n): ForwardedTokens =>\n Object.fromEntries(\n Object.entries(inputTokens).map(([source, tokens]) => [\n source,\n {\n idToken: tokens?.id_token,\n accessToken: tokens?.access_token,\n refreshToken: tokens?.refresh_token,\n },\n ]),\n );\n","import { AuthStorage, ForwardedTokensJWT, User } from \"@/types\";\nimport { UserStorage } from \"./types\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt\";\n\nexport interface UserSession {\n get(): User | null;\n set(user: User): void;\n}\n\nexport class GenericUserSession implements UserSession {\n constructor(readonly storage: AuthStorage) {}\n\n get(): User | null {\n const user = this.storage.get(UserStorage.USER);\n return user ? JSON.parse(user) : null;\n }\n\n set(user: User | null): void {\n const forwardedTokens = user?.forwardedTokens\n ? convertForwardedTokenFormat(user?.forwardedTokens as ForwardedTokensJWT)\n : null;\n const value = user ? JSON.stringify({ ...user, forwardedTokens }) : \"\";\n this.storage.set(UserStorage.USER, value);\n }\n}\n","import { retrieveTokens } from \"@/shared/util.js\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { AuthStorage, User } from \"@/types.js\";\n\nexport async function getUser(storage: AuthStorage): Promise<User | null> {\n const tokens = retrieveTokens(storage);\n if (!tokens) return null;\n\n // Assumes all information is in the ID token\n return (parseJWT(tokens.id_token)?.payload as User) ?? null;\n}\n","const DEFAULT_SCOPES = [\n \"openid\",\n \"profile\",\n \"email\",\n \"forwardedTokens\",\n \"offline_access\",\n];\nconst IFRAME_ID = \"civic-auth-iframe\";\n\nconst DEFAULT_AUTH_SERVER = \"https://auth.civic.com/oauth\";\n\nconst DEFAULT_OAUTH_GET_PARAMS = [\"code\", \"state\", \"iss\"];\n\n// The server's callback handler renders this text if it needs the front-end to make an additional token exchange call,\n// for the iframe case where cookies are not sent along with the initial redirect.\nconst TOKEN_EXCHANGE_TRIGGER_TEXT = \"sameDomainCodeExchangeRequired\";\n\nconst TOKEN_EXCHANGE_SUCCESS_TEXT = \"serverSideTokenExchangeSuccess\";\n\nconst DEFAULT_DISPLAY_MODE = \"iframe\";\nexport {\n DEFAULT_SCOPES,\n DEFAULT_OAUTH_GET_PARAMS,\n DEFAULT_DISPLAY_MODE,\n IFRAME_ID,\n DEFAULT_AUTH_SERVER,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n};\n","import { AuthStorage } from \"@/types\";\n\nexport class LocalStorageAdapter implements AuthStorage {\n get(key: string): string {\n return localStorage.getItem(key) || \"\";\n }\n\n set(key: string, value: string): void {\n localStorage.setItem(key, value);\n }\n}\n","import { deriveCodeChallenge } from \"@/shared/util.js\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.ts\";\nimport { AuthStorage } from \"@/types\";\nimport { CodeVerifier } from \"@/shared/types\";\n\n/** A PKCE consumer that retrieves the challenge from a server endpoint */\nexport class ConfidentialClientPKCEConsumer implements PKCEConsumer {\n constructor(private pkceChallengeEndpoint: string) {}\n async getCodeChallenge(): Promise<string> {\n const response = await fetch(this.pkceChallengeEndpoint);\n const data = (await response.json()) as { challenge: string };\n return data.challenge;\n }\n}\n\n/** A PKCE Producer that can generate and store a code verifier, but is agnostic as to the storage location */\nexport class GenericPublicClientPKCEProducer implements PKCEProducer {\n constructor(private storage: AuthStorage) {}\n\n // if there is already a verifier, return it,\n // If not, create a new one and store it\n async getCodeChallenge(): Promise<string> {\n // let verifier = await this.getCodeVerifier();\n // if (!verifier) {\n const verifier = generateCodeVerifier();\n this.storage.set(CodeVerifier.COOKIE_NAME, verifier);\n // }\n return deriveCodeChallenge(verifier);\n }\n // if there is already a verifier, return it,\n async getCodeVerifier(): Promise<string | null> {\n return this.storage.get(CodeVerifier.COOKIE_NAME);\n }\n}\n\n/** A PKCE Producer that is expected to run on a browser, and does not need a backend */\nexport class BrowserPublicClientPKCEProducer extends GenericPublicClientPKCEProducer {\n constructor() {\n super(new LocalStorageAdapter());\n }\n}\n","// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport {\n DisplayMode,\n Endpoints,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n PopupError,\n} from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage\";\n\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n oauthServer: string;\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n // the nonce to use for the login\n nonce?: string;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n console.log(\"BrowserAuthenticationInitiator constructor\", this.config);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n const url = await generateOauthLoginUrl(this.config);\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n console.log(\"Received invalid message from login app\", event.data);\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n console.log(\"Received message from login app\", event.data);\n this.handleLoginAppPopupFailed(loginMessage.data.url);\n }\n };\n window.addEventListener(\"message\", this.postMessageHandler);\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.setAttribute(\"src\", url.toString());\n }\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n console.log(\"signIn\", popupWindow);\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n return url;\n }\n\n async signOut(): Promise<URL> {\n const localStorage = new LocalStorageAdapter();\n clearTokens(localStorage);\n clearUser(localStorage);\n // TODO open the iframe or new tab etc: the logout URL is not currently\n // supported by on the oauth, so just clear state until then\n const url = await generateOauthLogoutUrl(this.config);\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n console.log(\"GenericAuthenticationInitiator constructor\", {\n config,\n });\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(): Promise<URL> {\n return generateOauthLogoutUrl(this.config);\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n console.log(\"BrowserAuthenticationService constructor\", {\n config,\n });\n super({\n ...config,\n state: generateState(config.displayMode),\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.config.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.config.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(new LocalStorageAdapter(), tokens);\n\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(new LocalStorageAdapter());\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n","import { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n // If an existing session is found, validate it and return the session data\n validateExistingSession(): Promise<SessionData>;\n}\n\nexport interface AuthenticationRefresher {\n refreshTokens: () => Promise<OIDCTokenResponseBody>;\n}\n\nexport class PopupError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, PopupError.prototype);\n }\n}\n","const isWindowInIframe = (window: Window): boolean => {\n if (typeof window !== \"undefined\") {\n // use the window width to determine if we're in an iframe or not\n try {\n if (window?.frameElement?.id === \"civic-auth-iframe\") {\n return true;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_e) {\n // If we get an error, we're not in an iframe\n return false;\n }\n }\n return false;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n try {\n window.history.replaceState({}, \"\", url);\n } catch (error) {\n console.warn(\"window.history.replaceState failed\", error);\n }\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n","import { LoginPostMessage } from \"@/types\";\n\nconst validateLoginAppPostMessage = (\n event: LoginPostMessage,\n clientId: string,\n): boolean => {\n const caseEvent = event as LoginPostMessage;\n console.log(\"caseEvent\", caseEvent);\n if (\n !caseEvent.clientId ||\n !caseEvent.data.url ||\n !caseEvent.source ||\n !caseEvent.type ||\n caseEvent.clientId !== clientId ||\n caseEvent.source !== \"civicloginApp\"\n ) {\n return false;\n }\n return true;\n};\n\nexport { validateLoginAppPostMessage };\n"],"mappings":"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","names":["OAuthTokens","OAuth2Client","window","localStorage","OAuth2Client"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-5UQQYXCX.js"],"names":[],"mappings":"AAAA","file":"/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-5UQQYXCX.js"}
1
+ {"version":3,"sources":["/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-5UQQYXCX.js"],"names":[],"mappings":"AAAA","file":"/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-5UQQYXCX.js"}
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkO2SODTR3js = require('./chunk-O2SODTR3.js');
10
+ var _chunk7K3QN2ATjs = require('./chunk-7K3QN2AT.js');
11
11
 
12
12
 
13
13
 
@@ -43,14 +43,14 @@ var ServerAuthenticationResolver = class _ServerAuthenticationResolver {
43
43
  storage,
44
44
  endpointOverrides
45
45
  });
46
- this.pkceProducer = new (0, _chunkO2SODTR3js.GenericPublicClientPKCEProducer)(storage);
46
+ this.pkceProducer = new (0, _chunk7K3QN2ATjs.GenericPublicClientPKCEProducer)(storage);
47
47
  }
48
48
  validateExistingSession() {
49
49
  throw new Error("Method not implemented.");
50
50
  }
51
51
  init() {
52
52
  return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
53
- this.endpoints = yield _chunkO2SODTR3js.getEndpointsWithOverrides.call(void 0,
53
+ this.endpoints = yield _chunk7K3QN2ATjs.getEndpointsWithOverrides.call(void 0,
54
54
  this.authConfig.oauthServer,
55
55
  this.endpointOverrides
56
56
  );
@@ -70,7 +70,7 @@ var ServerAuthenticationResolver = class _ServerAuthenticationResolver {
70
70
  if (!this.oauth2client) yield this.init();
71
71
  const codeVerifier = yield this.pkceProducer.getCodeVerifier();
72
72
  if (!codeVerifier) throw new Error("Code verifier not found in storage");
73
- const tokens = yield _chunkO2SODTR3js.exchangeTokens.call(void 0,
73
+ const tokens = yield _chunk7K3QN2ATjs.exchangeTokens.call(void 0,
74
74
  code,
75
75
  state,
76
76
  this.pkceProducer,
@@ -80,13 +80,13 @@ var ServerAuthenticationResolver = class _ServerAuthenticationResolver {
80
80
  this.endpoints
81
81
  // clean up types here to avoid the ! operator
82
82
  );
83
- _chunkO2SODTR3js.storeTokens.call(void 0, this.storage, tokens);
83
+ _chunk7K3QN2ATjs.storeTokens.call(void 0, this.storage, tokens);
84
84
  return tokens;
85
85
  });
86
86
  }
87
87
  getSessionData() {
88
88
  return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
89
- const storageData = _chunkO2SODTR3js.retrieveTokens.call(void 0, this.storage);
89
+ const storageData = _chunk7K3QN2ATjs.retrieveTokens.call(void 0, this.storage);
90
90
  if (!storageData) return null;
91
91
  return {
92
92
  authenticated: !!storageData.id_token,
@@ -115,7 +115,7 @@ function resolveOAuthAccessCode(code, state, storage, config) {
115
115
  var _a;
116
116
  const authSessionService = yield ServerAuthenticationResolver.build(
117
117
  _chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, config), {
118
- oauthServer: (_a = config.oauthServer) != null ? _a : _chunkO2SODTR3js.AUTH_SERVER
118
+ oauthServer: (_a = config.oauthServer) != null ? _a : _chunk7K3QN2ATjs.DEFAULT_AUTH_SERVER
119
119
  }),
120
120
  storage,
121
121
  config.endpointOverrides
@@ -130,12 +130,12 @@ function buildLoginUrl(config, storage) {
130
130
  return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
131
131
  var _a, _b, _c;
132
132
  const state = (_a = config.state) != null ? _a : Math.random().toString(36).substring(2);
133
- const scopes = (_b = config.scopes) != null ? _b : _chunkO2SODTR3js.DEFAULT_SCOPES;
134
- const pkceProducer = new (0, _chunkO2SODTR3js.GenericPublicClientPKCEProducer)(storage);
135
- const authInitiator = new (0, _chunkO2SODTR3js.GenericAuthenticationInitiator)(_chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, config), {
133
+ const scopes = (_b = config.scopes) != null ? _b : _chunk7K3QN2ATjs.DEFAULT_SCOPES;
134
+ const pkceProducer = new (0, _chunk7K3QN2ATjs.GenericPublicClientPKCEProducer)(storage);
135
+ const authInitiator = new (0, _chunk7K3QN2ATjs.GenericAuthenticationInitiator)(_chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, config), {
136
136
  state,
137
137
  scopes,
138
- oauthServer: (_c = config.oauthServer) != null ? _c : _chunkO2SODTR3js.AUTH_SERVER,
138
+ oauthServer: (_c = config.oauthServer) != null ? _c : _chunk7K3QN2ATjs.DEFAULT_AUTH_SERVER,
139
139
  // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session
140
140
  pkceConsumer: pkceProducer
141
141
  }));
@@ -157,7 +157,7 @@ var GenericAuthenticationRefresher = class _GenericAuthenticationRefresher {
157
157
  }
158
158
  init() {
159
159
  return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
160
- this.endpoints = yield _chunkO2SODTR3js.getEndpointsWithOverrides.call(void 0,
160
+ this.endpoints = yield _chunk7K3QN2ATjs.getEndpointsWithOverrides.call(void 0,
161
161
  this.authConfig.oauthServer,
162
162
  this.endpointOverrides
163
163
  );
@@ -186,13 +186,13 @@ var GenericAuthenticationRefresher = class _GenericAuthenticationRefresher {
186
186
  refreshTokens() {
187
187
  return _chunkCRTRMMJ7js.__async.call(void 0, this, null, function* () {
188
188
  if (!this.oauth2client) yield this.init();
189
- const tokens = _chunkO2SODTR3js.retrieveTokens.call(void 0, this.storage);
189
+ const tokens = _chunk7K3QN2ATjs.retrieveTokens.call(void 0, this.storage);
190
190
  if (!(tokens == null ? void 0 : tokens.refresh_token)) throw new Error("No refresh token available");
191
191
  const oauth2Client = this.oauth2client;
192
192
  const refreshedTokens = yield oauth2Client.refreshAccessToken(
193
193
  tokens.refresh_token
194
194
  );
195
- _chunkO2SODTR3js.storeTokens.call(void 0, this.storage, refreshedTokens);
195
+ _chunk7K3QN2ATjs.storeTokens.call(void 0, this.storage, refreshedTokens);
196
196
  return tokens;
197
197
  });
198
198
  }
@@ -204,7 +204,7 @@ function refreshTokens(storage, config) {
204
204
  var _a;
205
205
  const refresher = yield GenericAuthenticationRefresher.build(
206
206
  _chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, config), {
207
- oauthServer: (_a = config.oauthServer) != null ? _a : _chunkO2SODTR3js.AUTH_SERVER
207
+ oauthServer: (_a = config.oauthServer) != null ? _a : _chunk7K3QN2ATjs.DEFAULT_AUTH_SERVER
208
208
  }),
209
209
  storage,
210
210
  config.endpointOverrides
@@ -220,4 +220,4 @@ function refreshTokens(storage, config) {
220
220
 
221
221
 
222
222
  exports.CookieStorage = CookieStorage; exports.resolveOAuthAccessCode = resolveOAuthAccessCode; exports.isLoggedIn = isLoggedIn; exports.buildLoginUrl = buildLoginUrl; exports.refreshTokens = refreshTokens;
223
- //# sourceMappingURL=chunk-O6DPCPRH.js.map
223
+ //# sourceMappingURL=chunk-6RFRDWIP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-6RFRDWIP.js","../src/shared/storage.ts","../src/server/ServerAuthenticationResolver.ts","../src/server/login.ts","../src/shared/GenericAuthenticationRefresher.ts","../src/server/refresh.ts"],"names":["OAuth2Client"],"mappings":"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","file":"/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-6RFRDWIP.js","sourcesContent":[null,"import { AuthStorage, SessionData, UnknownObject, User } from \"@/types.js\";\n\ntype SameSiteOption = \"strict\" | \"lax\" | \"none\";\n\nexport interface SessionStorage {\n get(): SessionData;\n getUser(): User<UnknownObject> | null;\n set(data: Partial<SessionData>): void;\n setUser(data: User<UnknownObject> | null): void;\n clear(): void;\n}\n\nexport type CookieStorageSettings = {\n httpOnly: boolean;\n secure: boolean;\n sameSite: SameSiteOption;\n expires: Date;\n path: string;\n};\n\nexport const DEFAULT_COOKIE_DURATION = 60 * 15; // 15 minutes\n\nexport abstract class CookieStorage implements AuthStorage {\n protected settings: CookieStorageSettings;\n protected constructor(settings: Partial<CookieStorageSettings> = {}) {\n this.settings = {\n httpOnly: settings.httpOnly ?? true,\n secure: settings.secure ?? true,\n // the callback request comes the auth server\n // 'lax' ensures the code_verifier cookie is sent with the request\n sameSite: settings.sameSite ?? \"lax\",\n expires:\n settings.expires ??\n new Date(Date.now() + 1000 * DEFAULT_COOKIE_DURATION),\n path: settings.path ?? \"/\",\n };\n }\n abstract get(key: string): string | null;\n abstract set(key: string, value: string): void;\n}\n","import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.js\";\nimport { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n console.log(\"ServerAuthenticationResolver constructor\", {\n authConfig,\n storage,\n endpointOverrides,\n });\n this.pkceProducer = new GenericPublicClientPKCEProducer(storage);\n }\n validateExistingSession(): Promise<SessionData> {\n throw new Error(\"Method not implemented.\");\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.authConfig.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(this.storage, tokens);\n\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from \"@/constants.js\";\nimport { GenericAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport { AuthConfig } from \"@/server/config.ts\";\n/**\n * Resolve an OAuth access code to a set of OIDC tokens\n * @param code The access code, typically from a query parameter in the redirect url\n * @param state The oauth random state string, used to distinguish between requests. Typically also passed in the redirect url\n * @param storage The place that this server uses to store session data (e.g. a cookie store)\n * @param config Oauth Server configuration\n */\nexport async function resolveOAuthAccessCode(\n code: string,\n state: string,\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return authSessionService.tokenExchange(code, state);\n}\n\nexport function isLoggedIn(storage: AuthStorage): boolean {\n return !!storage.get(\"id_token\");\n}\n\nexport async function buildLoginUrl(\n config: Pick<AuthConfig, \"oauthServer\" | \"clientId\" | \"redirectUrl\"> & {\n scopes?: string[];\n state?: string;\n nonce?: string;\n },\n storage: AuthStorage,\n): Promise<URL> {\n // generate a random state if not provided\n const state = config.state ?? Math.random().toString(36).substring(2);\n const scopes = config.scopes ?? DEFAULT_SCOPES;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n const authInitiator = new GenericAuthenticationInitiator({\n ...config,\n state,\n scopes,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session\n pkceConsumer: pkceProducer,\n });\n\n return authInitiator.signIn();\n}\n","import { AuthenticationRefresher } from \"@/services/types.ts\";\nimport { AuthStorage, Endpoints, OIDCTokenResponseBody } from \"@/types\";\nimport {\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\nimport { OAuth2Client } from \"oslo/oauth2\";\n\nexport class GenericAuthenticationRefresher implements AuthenticationRefresher {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n private authConfig: AuthConfig,\n private storage: AuthStorage,\n private endpointOverrides?: Partial<Endpoints>,\n ) {\n console.log(\"GenericAuthenticationRefresher constructor\", {\n authConfig,\n endpointOverrides,\n });\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<GenericAuthenticationRefresher> {\n const refresher = new GenericAuthenticationRefresher(\n authConfig,\n storage,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n\n async refreshTokens() {\n if (!this.oauth2client) await this.init();\n\n const tokens = retrieveTokens(this.storage);\n if (!tokens?.refresh_token) throw new Error(\"No refresh token available\");\n\n const oauth2Client = this.oauth2client!;\n const refreshedTokens =\n await oauth2Client.refreshAccessToken<OIDCTokenResponseBody>(\n tokens.refresh_token,\n );\n\n storeTokens(this.storage, refreshedTokens);\n\n return tokens;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { GenericAuthenticationRefresher } from \"@/shared/GenericAuthenticationRefresher.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\n\n/**\n * Refresh the current set of OIDC tokens\n */\nexport async function refreshTokens(\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const refresher = await GenericAuthenticationRefresher.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return refresher.refreshTokens();\n}\n"]}
@@ -256,7 +256,7 @@ var DEFAULT_SCOPES = [
256
256
  "offline_access"
257
257
  ];
258
258
  var IFRAME_ID = "civic-auth-iframe";
259
- var AUTH_SERVER = "https://auth-dev.civic.com/oauth";
259
+ var DEFAULT_AUTH_SERVER = "https://auth.civic.com/oauth";
260
260
  var DEFAULT_OAUTH_GET_PARAMS = ["code", "state", "iss"];
261
261
  var TOKEN_EXCHANGE_TRIGGER_TEXT = "sameDomainCodeExchangeRequired";
262
262
  var TOKEN_EXCHANGE_SUCCESS_TEXT = "serverSideTokenExchangeSuccess";
@@ -595,5 +595,5 @@ var BrowserAuthenticationService = class _BrowserAuthenticationService extends B
595
595
 
596
596
 
597
597
 
598
- exports.convertForwardedTokenFormat = convertForwardedTokenFormat; exports.GenericUserSession = GenericUserSession; exports.DEFAULT_SCOPES = DEFAULT_SCOPES; exports.IFRAME_ID = IFRAME_ID; exports.AUTH_SERVER = AUTH_SERVER; exports.TOKEN_EXCHANGE_TRIGGER_TEXT = TOKEN_EXCHANGE_TRIGGER_TEXT; exports.TOKEN_EXCHANGE_SUCCESS_TEXT = TOKEN_EXCHANGE_SUCCESS_TEXT; exports.isWindowInIframe = isWindowInIframe; exports.generateState = generateState; exports.serverTokenExchangeFromState = serverTokenExchangeFromState; exports.cn = cn; exports.withoutUndefined = withoutUndefined; exports.getEndpointsWithOverrides = getEndpointsWithOverrides; exports.exchangeTokens = exchangeTokens; exports.storeTokens = storeTokens; exports.clearTokens = clearTokens; exports.retrieveTokens = retrieveTokens; exports.LocalStorageAdapter = LocalStorageAdapter; exports.ConfidentialClientPKCEConsumer = ConfidentialClientPKCEConsumer; exports.GenericPublicClientPKCEProducer = GenericPublicClientPKCEProducer; exports.BrowserPublicClientPKCEProducer = BrowserPublicClientPKCEProducer; exports.PopupError = PopupError; exports.BrowserAuthenticationInitiator = BrowserAuthenticationInitiator; exports.GenericAuthenticationInitiator = GenericAuthenticationInitiator; exports.BrowserAuthenticationService = BrowserAuthenticationService; exports.getUser = getUser;
599
- //# sourceMappingURL=chunk-O2SODTR3.js.map
598
+ exports.convertForwardedTokenFormat = convertForwardedTokenFormat; exports.GenericUserSession = GenericUserSession; exports.DEFAULT_SCOPES = DEFAULT_SCOPES; exports.IFRAME_ID = IFRAME_ID; exports.DEFAULT_AUTH_SERVER = DEFAULT_AUTH_SERVER; exports.TOKEN_EXCHANGE_TRIGGER_TEXT = TOKEN_EXCHANGE_TRIGGER_TEXT; exports.TOKEN_EXCHANGE_SUCCESS_TEXT = TOKEN_EXCHANGE_SUCCESS_TEXT; exports.isWindowInIframe = isWindowInIframe; exports.generateState = generateState; exports.serverTokenExchangeFromState = serverTokenExchangeFromState; exports.cn = cn; exports.withoutUndefined = withoutUndefined; exports.getEndpointsWithOverrides = getEndpointsWithOverrides; exports.exchangeTokens = exchangeTokens; exports.storeTokens = storeTokens; exports.clearTokens = clearTokens; exports.retrieveTokens = retrieveTokens; exports.LocalStorageAdapter = LocalStorageAdapter; exports.ConfidentialClientPKCEConsumer = ConfidentialClientPKCEConsumer; exports.GenericPublicClientPKCEProducer = GenericPublicClientPKCEProducer; exports.BrowserPublicClientPKCEProducer = BrowserPublicClientPKCEProducer; exports.PopupError = PopupError; exports.BrowserAuthenticationInitiator = BrowserAuthenticationInitiator; exports.GenericAuthenticationInitiator = GenericAuthenticationInitiator; exports.BrowserAuthenticationService = BrowserAuthenticationService; exports.getUser = getUser;
599
+ //# sourceMappingURL=chunk-7K3QN2AT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-7K3QN2AT.js","../src/shared/types.ts","../src/shared/util.ts","../src/lib/oauth.ts","../src/utils.ts","../src/lib/jwt.ts","../src/shared/UserSession.ts","../src/shared/session.ts","../src/constants.ts","../src/browser/storage.ts","../src/services/PKCE.ts","../src/services/AuthenticationService.ts","../src/services/types.ts","../src/lib/windowUtil.ts","../src/lib/postMessage.ts"],"names":["OAuthTokens","OAuth2Client","window","localStorage"],"mappings":"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","file":"/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-7K3QN2AT.js","sourcesContent":[null,"export enum OAuthTokens {\n ID_TOKEN = \"id_token\",\n ACCESS_TOKEN = \"access_token\",\n REFRESH_TOKEN = \"refresh_token\",\n}\n\nexport enum CodeVerifier {\n COOKIE_NAME = \"code_verifier\",\n}\nexport enum UserStorage {\n USER = \"user\",\n}\nexport interface CookieConfig {\n secure?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n domain?: string;\n path?: string;\n maxAge?: number;\n httpOnly?: boolean;\n}\n\nexport type TokensCookieConfig = Record<\n OAuthTokens | CodeVerifier,\n CookieConfig\n>;\n","// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\n\nimport {\n AuthStorage,\n Endpoints,\n JWTPayload,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport { CodeVerifier, OAuthTokens } from \"./types\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { getIssuerVariations, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport * as jose from \"jose\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"./UserSession\";\n\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n) {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n const challenge = await config.pkceConsumer.getCodeChallenge();\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n console.log(\"Generated OAuth URL\", oAuthUrl.toString());\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n // TODO\n return new URL(\"http://localhost\");\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer,\n oauth2Client: OAuth2Client,\n oauthServer: string,\n endpoints: Endpoints,\n) {\n const codeVerifier = await pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in state\");\n\n const tokens =\n await oauth2Client.validateAuthorizationCode<OIDCTokenResponseBody>(code, {\n codeVerifier,\n });\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(tokens, endpoints, oauth2Client, oauthServer);\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n\n return tokens;\n}\n\nexport function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // store tokens in storage ( TODO we should probably store them against the state to allow multiple logins )\n storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);\n storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);\n if (tokens.refresh_token)\n storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);\n}\n\nexport function clearTokens(storage: AuthStorage) {\n Object.values(OAuthTokens).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n Object.values(CodeVerifier.COOKIE_NAME).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n}\nexport function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n userSession.set(null);\n}\n\nexport function retrieveTokens(\n storage: AuthStorage,\n): OIDCTokenResponseBody | null {\n const idToken = storage.get(OAuthTokens.ID_TOKEN);\n const accessToken = storage.get(OAuthTokens.ACCESS_TOKEN);\n const refreshToken = storage.get(OAuthTokens.REFRESH_TOKEN);\n\n if (!idToken || !accessToken) return null;\n\n return {\n id_token: idToken,\n access_token: accessToken,\n refresh_token: refreshToken ?? undefined,\n };\n}\n\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n endpoints: Endpoints,\n oauth2Client: OAuth2Client,\n issuer: string,\n): Promise<ParsedTokens> {\n const JWKS = jose.createRemoteJWKSet(new URL(endpoints.jwks));\n\n // validate the ID token\n const idTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.id_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n audience: oauth2Client.clientId,\n },\n );\n\n // validate the access token\n const accessTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.access_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n },\n );\n\n return withoutUndefined({\n id_token: idTokenResponse.payload,\n access_token: accessTokenResponse.payload,\n refresh_token: tokens.refresh_token,\n });\n}\n","import { DisplayMode, Endpoints, OpenIdConfiguration } from \"@/types\";\nimport { v4 as uuid } from \"uuid\";\n\nconst getIssuerVariations = (issuer: string): string[] => {\n const issuerWithoutSlash = issuer.endsWith(\"/\")\n ? issuer.slice(0, issuer.length - 1)\n : issuer;\n\n const issuerWithSlash = `${issuerWithoutSlash}/`;\n\n return [issuerWithoutSlash, issuerWithSlash];\n};\n\nconst addSlashIfNeeded = (url: string): string =>\n url.endsWith(\"/\") ? url : `${url}/`;\n\nconst getOauthEndpoints = async (oauthServer: string): Promise<Endpoints> => {\n const openIdConfigResponse = await fetch(\n `${addSlashIfNeeded(oauthServer)}.well-known/openid-configuration`,\n );\n const openIdConfig =\n (await openIdConfigResponse.json()) as OpenIdConfiguration;\n return {\n jwks: openIdConfig.jwks_uri,\n auth: openIdConfig.authorization_endpoint,\n token: openIdConfig.token_endpoint,\n userinfo: openIdConfig.userinfo_endpoint,\n };\n};\n\n/**\n * creates a state string for the OAuth2 flow, encoding the display mode too for future use\n * @param {DisplayMode} displayMode\n * @returns {string}\n */\nconst generateState = (\n displayMode: DisplayMode,\n serverTokenExchange?: boolean,\n): string => {\n const jsonString = JSON.stringify({\n uuid: uuid(),\n displayMode,\n ...(serverTokenExchange ? { serverTokenExchange } : {}),\n });\n return btoa(jsonString);\n};\n\n/**\n * parses the state string from the OAuth2 flow, decoding the display mode too\n * @param state\n * @param sessionDisplayMode\n * @returns { uuid: string, displayMode: DisplayMode }\n */\nconst displayModeFromState = (\n state: string,\n sessionDisplayMode: DisplayMode | undefined,\n): DisplayMode | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).displayMode;\n } catch {\n console.error(\"Failed to parse displayMode from state:\", state);\n return sessionDisplayMode;\n }\n};\n\nconst serverTokenExchangeFromState = (state: string): boolean | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).serverTokenExchange;\n } catch {\n console.error(\"Failed to parse serverTokenExchange from state:\", state);\n return undefined;\n }\n};\n\nexport {\n serverTokenExchangeFromState,\n getIssuerVariations,\n getOauthEndpoints,\n displayModeFromState,\n generateState,\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Checks if a popup window is blocked by the browser.\n *\n * This function attempts to open a small popup window and then checks if it was successfully created.\n * If the popup is blocked by the browser, the function returns `true`. Otherwise, it returns `false`.\n *\n * @returns {boolean} - `true` if the popup is blocked, `false` otherwise.\n */\nconst isPopupBlocked = (): boolean => {\n // First we try to open a small popup window. It either returns a window object or null.\n const popup = window.open(\"\", \"\", \"width=1,height=1\");\n\n // If window.open() returns null, popup is definitely blocked\n if (!popup) {\n return true;\n }\n\n try {\n // Try to access a property of the popup to check if it's usable\n if (typeof popup.closed === \"undefined\") {\n throw new Error(\"Popup is blocked\");\n }\n } catch {\n // Accessing the popup's properties throws an error if the popup is blocked\n return true;\n }\n\n // Close the popup immediately if it was opened\n popup.close();\n return false;\n};\n\nconst cn = (...inputs: ClassValue[]) => {\n return twMerge(clsx(inputs));\n};\n\n// This type narrows T as far as it can by:\n// - removing all keys where the value is `undefined`\n// - making keys that are not undefined required\n// So, for example: given { a: string | undefined, b: string | undefined },\n// if you pass in { a: \"foo\" }, it returns an object of type: { a: string }\ntype WithoutUndefined<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K];\n};\nexport const withoutUndefined = <T extends { [K in keyof T]: unknown }>(\n obj: T,\n): WithoutUndefined<T> => {\n const result = {} as WithoutUndefined<T>;\n\n for (const key in obj) {\n if (obj[key] !== undefined) {\n // TypeScript needs assurance that key is a valid key in WithoutUndefined<T>\n // We use type assertion here\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (result as any)[key] = obj[key];\n }\n }\n\n return result;\n};\n\nexport { cn, isPopupBlocked };\n","import { ForwardedTokens, ForwardedTokensJWT } from \"@/types.js\";\n\nexport const convertForwardedTokenFormat = (\n inputTokens: ForwardedTokensJWT,\n): ForwardedTokens =>\n Object.fromEntries(\n Object.entries(inputTokens).map(([source, tokens]) => [\n source,\n {\n idToken: tokens?.id_token,\n accessToken: tokens?.access_token,\n refreshToken: tokens?.refresh_token,\n },\n ]),\n );\n","import { AuthStorage, ForwardedTokensJWT, User } from \"@/types\";\nimport { UserStorage } from \"./types\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt\";\n\nexport interface UserSession {\n get(): User | null;\n set(user: User): void;\n}\n\nexport class GenericUserSession implements UserSession {\n constructor(readonly storage: AuthStorage) {}\n\n get(): User | null {\n const user = this.storage.get(UserStorage.USER);\n return user ? JSON.parse(user) : null;\n }\n\n set(user: User | null): void {\n const forwardedTokens = user?.forwardedTokens\n ? convertForwardedTokenFormat(user?.forwardedTokens as ForwardedTokensJWT)\n : null;\n const value = user ? JSON.stringify({ ...user, forwardedTokens }) : \"\";\n this.storage.set(UserStorage.USER, value);\n }\n}\n","import { retrieveTokens } from \"@/shared/util.js\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { AuthStorage, User } from \"@/types.js\";\n\nexport async function getUser(storage: AuthStorage): Promise<User | null> {\n const tokens = retrieveTokens(storage);\n if (!tokens) return null;\n\n // Assumes all information is in the ID token\n return (parseJWT(tokens.id_token)?.payload as User) ?? null;\n}\n","const DEFAULT_SCOPES = [\n \"openid\",\n \"profile\",\n \"email\",\n \"forwardedTokens\",\n \"offline_access\",\n];\nconst IFRAME_ID = \"civic-auth-iframe\";\n\nconst DEFAULT_AUTH_SERVER = \"https://auth.civic.com/oauth\";\n\nconst DEFAULT_OAUTH_GET_PARAMS = [\"code\", \"state\", \"iss\"];\n\n// The server's callback handler renders this text if it needs the front-end to make an additional token exchange call,\n// for the iframe case where cookies are not sent along with the initial redirect.\nconst TOKEN_EXCHANGE_TRIGGER_TEXT = \"sameDomainCodeExchangeRequired\";\n\nconst TOKEN_EXCHANGE_SUCCESS_TEXT = \"serverSideTokenExchangeSuccess\";\n\nconst DEFAULT_DISPLAY_MODE = \"iframe\";\nexport {\n DEFAULT_SCOPES,\n DEFAULT_OAUTH_GET_PARAMS,\n DEFAULT_DISPLAY_MODE,\n IFRAME_ID,\n DEFAULT_AUTH_SERVER,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n};\n","import { AuthStorage } from \"@/types\";\n\nexport class LocalStorageAdapter implements AuthStorage {\n get(key: string): string {\n return localStorage.getItem(key) || \"\";\n }\n\n set(key: string, value: string): void {\n localStorage.setItem(key, value);\n }\n}\n","import { deriveCodeChallenge } from \"@/shared/util.js\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.ts\";\nimport { AuthStorage } from \"@/types\";\nimport { CodeVerifier } from \"@/shared/types\";\n\n/** A PKCE consumer that retrieves the challenge from a server endpoint */\nexport class ConfidentialClientPKCEConsumer implements PKCEConsumer {\n constructor(private pkceChallengeEndpoint: string) {}\n async getCodeChallenge(): Promise<string> {\n const response = await fetch(this.pkceChallengeEndpoint);\n const data = (await response.json()) as { challenge: string };\n return data.challenge;\n }\n}\n\n/** A PKCE Producer that can generate and store a code verifier, but is agnostic as to the storage location */\nexport class GenericPublicClientPKCEProducer implements PKCEProducer {\n constructor(private storage: AuthStorage) {}\n\n // if there is already a verifier, return it,\n // If not, create a new one and store it\n async getCodeChallenge(): Promise<string> {\n // let verifier = await this.getCodeVerifier();\n // if (!verifier) {\n const verifier = generateCodeVerifier();\n this.storage.set(CodeVerifier.COOKIE_NAME, verifier);\n // }\n return deriveCodeChallenge(verifier);\n }\n // if there is already a verifier, return it,\n async getCodeVerifier(): Promise<string | null> {\n return this.storage.get(CodeVerifier.COOKIE_NAME);\n }\n}\n\n/** A PKCE Producer that is expected to run on a browser, and does not need a backend */\nexport class BrowserPublicClientPKCEProducer extends GenericPublicClientPKCEProducer {\n constructor() {\n super(new LocalStorageAdapter());\n }\n}\n","// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport {\n DisplayMode,\n Endpoints,\n LoginPostMessage,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n PopupError,\n} from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants\";\nimport { validateLoginAppPostMessage } from \"@/lib/postMessage\";\n\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n private postMessageHandler: null | ((event: MessageEvent) => void) = null;\n\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n oauthServer: string;\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n // the nonce to use for the login\n nonce?: string;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n console.log(\"BrowserAuthenticationInitiator constructor\", this.config);\n }\n\n async handleLoginAppPopupFailed(redirectUrl: string) {\n console.warn(\n \"Login app popup failed open a popup, using redirect mode instead...\",\n redirectUrl,\n );\n window.location.href = redirectUrl;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n const url = await generateOauthLoginUrl(this.config);\n\n this.postMessageHandler = (event: MessageEvent) => {\n const thisURL = new URL(window.location.href);\n if (\n event.origin.endsWith(\"civic.com\") ||\n thisURL.hostname === \"localhost\"\n ) {\n if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {\n console.log(\"Received invalid message from login app\", event.data);\n return;\n }\n const loginMessage = event.data as LoginPostMessage;\n console.log(\"Received message from login app\", event.data);\n this.handleLoginAppPopupFailed(loginMessage.data.url);\n }\n };\n window.addEventListener(\"message\", this.postMessageHandler);\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.setAttribute(\"src\", url.toString());\n }\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n if (this.config.displayMode === \"new_tab\") {\n try {\n const popupWindow = window.open(url.toString(), \"_blank\");\n console.log(\"signIn\", popupWindow);\n if (!popupWindow) {\n throw new PopupError(\"Failed to open popup window\");\n }\n } catch (error) {\n console.error(\"popupWindow\", error);\n throw new PopupError(\n \"window.open has thrown: Failed to open popup window\",\n );\n }\n }\n return url;\n }\n\n async signOut(): Promise<URL> {\n const localStorage = new LocalStorageAdapter();\n clearTokens(localStorage);\n clearUser(localStorage);\n // TODO open the iframe or new tab etc: the logout URL is not currently\n // supported by on the oauth, so just clear state until then\n const url = await generateOauthLogoutUrl(this.config);\n return url;\n }\n\n cleanup() {\n if (this.postMessageHandler) {\n window.removeEventListener(\"message\", this.postMessageHandler);\n }\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n console.log(\"GenericAuthenticationInitiator constructor\", {\n config,\n });\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(): Promise<URL> {\n return generateOauthLogoutUrl(this.config);\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n console.log(\"BrowserAuthenticationService constructor\", {\n config,\n });\n super({\n ...config,\n state: generateState(config.displayMode),\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.config.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.config.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(new LocalStorageAdapter(), tokens);\n\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.close();\n }\n // these are the default oAuth params that get added to the URL in redirect which we want to remove if present\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(new LocalStorageAdapter());\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n","import { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n // If an existing session is found, validate it and return the session data\n validateExistingSession(): Promise<SessionData>;\n}\n\nexport interface AuthenticationRefresher {\n refreshTokens: () => Promise<OIDCTokenResponseBody>;\n}\n\nexport class PopupError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, PopupError.prototype);\n }\n}\n","const isWindowInIframe = (window: Window): boolean => {\n if (typeof window !== \"undefined\") {\n // use the window width to determine if we're in an iframe or not\n try {\n if (window?.frameElement?.id === \"civic-auth-iframe\") {\n return true;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_e) {\n // If we get an error, we're not in an iframe\n return false;\n }\n }\n return false;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n try {\n window.history.replaceState({}, \"\", url);\n } catch (error) {\n console.warn(\"window.history.replaceState failed\", error);\n }\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n","import { LoginPostMessage } from \"@/types\";\n\nconst validateLoginAppPostMessage = (\n event: LoginPostMessage,\n clientId: string,\n): boolean => {\n const caseEvent = event as LoginPostMessage;\n console.log(\"caseEvent\", caseEvent);\n if (\n !caseEvent.clientId ||\n !caseEvent.data.url ||\n !caseEvent.source ||\n !caseEvent.type ||\n caseEvent.clientId !== clientId ||\n caseEvent.source !== \"civicloginApp\"\n ) {\n return false;\n }\n return true;\n};\n\nexport { validateLoginAppPostMessage };\n"]}
@@ -1,5 +1,5 @@
1
1
  import {
2
- AUTH_SERVER,
2
+ DEFAULT_AUTH_SERVER,
3
3
  DEFAULT_SCOPES,
4
4
  GenericAuthenticationInitiator,
5
5
  GenericPublicClientPKCEProducer,
@@ -7,7 +7,7 @@ import {
7
7
  getEndpointsWithOverrides,
8
8
  retrieveTokens,
9
9
  storeTokens
10
- } from "./chunk-CBQ3HKRV.mjs";
10
+ } from "./chunk-4PLCDPEN.mjs";
11
11
  import {
12
12
  __async,
13
13
  __spreadProps,
@@ -115,7 +115,7 @@ function resolveOAuthAccessCode(code, state, storage, config) {
115
115
  var _a;
116
116
  const authSessionService = yield ServerAuthenticationResolver.build(
117
117
  __spreadProps(__spreadValues({}, config), {
118
- oauthServer: (_a = config.oauthServer) != null ? _a : AUTH_SERVER
118
+ oauthServer: (_a = config.oauthServer) != null ? _a : DEFAULT_AUTH_SERVER
119
119
  }),
120
120
  storage,
121
121
  config.endpointOverrides
@@ -135,7 +135,7 @@ function buildLoginUrl(config, storage) {
135
135
  const authInitiator = new GenericAuthenticationInitiator(__spreadProps(__spreadValues({}, config), {
136
136
  state,
137
137
  scopes,
138
- oauthServer: (_c = config.oauthServer) != null ? _c : AUTH_SERVER,
138
+ oauthServer: (_c = config.oauthServer) != null ? _c : DEFAULT_AUTH_SERVER,
139
139
  // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session
140
140
  pkceConsumer: pkceProducer
141
141
  }));
@@ -204,7 +204,7 @@ function refreshTokens(storage, config) {
204
204
  var _a;
205
205
  const refresher = yield GenericAuthenticationRefresher.build(
206
206
  __spreadProps(__spreadValues({}, config), {
207
- oauthServer: (_a = config.oauthServer) != null ? _a : AUTH_SERVER
207
+ oauthServer: (_a = config.oauthServer) != null ? _a : DEFAULT_AUTH_SERVER
208
208
  }),
209
209
  storage,
210
210
  config.endpointOverrides
@@ -220,4 +220,4 @@ export {
220
220
  buildLoginUrl,
221
221
  refreshTokens
222
222
  };
223
- //# sourceMappingURL=chunk-HTTTZ2BP.mjs.map
223
+ //# sourceMappingURL=chunk-AP4627CS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/storage.ts","../src/server/ServerAuthenticationResolver.ts","../src/server/login.ts","../src/shared/GenericAuthenticationRefresher.ts","../src/server/refresh.ts"],"sourcesContent":["import { AuthStorage, SessionData, UnknownObject, User } from \"@/types.js\";\n\ntype SameSiteOption = \"strict\" | \"lax\" | \"none\";\n\nexport interface SessionStorage {\n get(): SessionData;\n getUser(): User<UnknownObject> | null;\n set(data: Partial<SessionData>): void;\n setUser(data: User<UnknownObject> | null): void;\n clear(): void;\n}\n\nexport type CookieStorageSettings = {\n httpOnly: boolean;\n secure: boolean;\n sameSite: SameSiteOption;\n expires: Date;\n path: string;\n};\n\nexport const DEFAULT_COOKIE_DURATION = 60 * 15; // 15 minutes\n\nexport abstract class CookieStorage implements AuthStorage {\n protected settings: CookieStorageSettings;\n protected constructor(settings: Partial<CookieStorageSettings> = {}) {\n this.settings = {\n httpOnly: settings.httpOnly ?? true,\n secure: settings.secure ?? true,\n // the callback request comes the auth server\n // 'lax' ensures the code_verifier cookie is sent with the request\n sameSite: settings.sameSite ?? \"lax\",\n expires:\n settings.expires ??\n new Date(Date.now() + 1000 * DEFAULT_COOKIE_DURATION),\n path: settings.path ?? \"/\",\n };\n }\n abstract get(key: string): string | null;\n abstract set(key: string, value: string): void;\n}\n","import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.js\";\nimport { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n console.log(\"ServerAuthenticationResolver constructor\", {\n authConfig,\n storage,\n endpointOverrides,\n });\n this.pkceProducer = new GenericPublicClientPKCEProducer(storage);\n }\n validateExistingSession(): Promise<SessionData> {\n throw new Error(\"Method not implemented.\");\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.authConfig.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(this.storage, tokens);\n\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from \"@/constants.js\";\nimport { GenericAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport { AuthConfig } from \"@/server/config.ts\";\n/**\n * Resolve an OAuth access code to a set of OIDC tokens\n * @param code The access code, typically from a query parameter in the redirect url\n * @param state The oauth random state string, used to distinguish between requests. Typically also passed in the redirect url\n * @param storage The place that this server uses to store session data (e.g. a cookie store)\n * @param config Oauth Server configuration\n */\nexport async function resolveOAuthAccessCode(\n code: string,\n state: string,\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return authSessionService.tokenExchange(code, state);\n}\n\nexport function isLoggedIn(storage: AuthStorage): boolean {\n return !!storage.get(\"id_token\");\n}\n\nexport async function buildLoginUrl(\n config: Pick<AuthConfig, \"oauthServer\" | \"clientId\" | \"redirectUrl\"> & {\n scopes?: string[];\n state?: string;\n nonce?: string;\n },\n storage: AuthStorage,\n): Promise<URL> {\n // generate a random state if not provided\n const state = config.state ?? Math.random().toString(36).substring(2);\n const scopes = config.scopes ?? DEFAULT_SCOPES;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n const authInitiator = new GenericAuthenticationInitiator({\n ...config,\n state,\n scopes,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session\n pkceConsumer: pkceProducer,\n });\n\n return authInitiator.signIn();\n}\n","import { AuthenticationRefresher } from \"@/services/types.ts\";\nimport { AuthStorage, Endpoints, OIDCTokenResponseBody } from \"@/types\";\nimport {\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\nimport { OAuth2Client } from \"oslo/oauth2\";\n\nexport class GenericAuthenticationRefresher implements AuthenticationRefresher {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n private authConfig: AuthConfig,\n private storage: AuthStorage,\n private endpointOverrides?: Partial<Endpoints>,\n ) {\n console.log(\"GenericAuthenticationRefresher constructor\", {\n authConfig,\n endpointOverrides,\n });\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<GenericAuthenticationRefresher> {\n const refresher = new GenericAuthenticationRefresher(\n authConfig,\n storage,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n\n async refreshTokens() {\n if (!this.oauth2client) await this.init();\n\n const tokens = retrieveTokens(this.storage);\n if (!tokens?.refresh_token) throw new Error(\"No refresh token available\");\n\n const oauth2Client = this.oauth2client!;\n const refreshedTokens =\n await oauth2Client.refreshAccessToken<OIDCTokenResponseBody>(\n tokens.refresh_token,\n );\n\n storeTokens(this.storage, refreshedTokens);\n\n return tokens;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { GenericAuthenticationRefresher } from \"@/shared/GenericAuthenticationRefresher.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\n\n/**\n * Refresh the current set of OIDC tokens\n */\nexport async function refreshTokens(\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const refresher = await GenericAuthenticationRefresher.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return refresher.refreshTokens();\n}\n"],"mappings":"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","names":["OAuth2Client","OAuth2Client"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-CRTRMMJ7.js"],"names":[],"mappings":"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","file":"/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-CRTRMMJ7.js"}
1
+ {"version":3,"sources":["/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-CRTRMMJ7.js"],"names":[],"mappings":"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","file":"/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-CRTRMMJ7.js"}
@@ -1,10 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkO6DPCPRHjs = require('./chunk-O6DPCPRH.js');
3
+ var _chunk6RFRDWIPjs = require('./chunk-6RFRDWIP.js');
4
4
 
5
5
 
6
6
 
7
- var _chunkO2SODTR3js = require('./chunk-O2SODTR3.js');
7
+ var _chunk7K3QN2ATjs = require('./chunk-7K3QN2AT.js');
8
8
 
9
9
 
10
10
 
@@ -52,12 +52,12 @@ var createUserInfoCookie = (response, user, sessionData, config) => {
52
52
  var clearAuthCookies = (config) => _chunkCRTRMMJ7js.__async.call(void 0, void 0, null, function* () {
53
53
  var _a;
54
54
  const cookieStorage = new NextjsCookieStorage((_a = config.cookies) == null ? void 0 : _a.tokens);
55
- _chunkO2SODTR3js.clearTokens.call(void 0, cookieStorage);
55
+ _chunk7K3QN2ATjs.clearTokens.call(void 0, cookieStorage);
56
56
  const clientStorage = new NextjsClientStorage();
57
- const userSession = new (0, _chunkO2SODTR3js.GenericUserSession)(clientStorage);
57
+ const userSession = new (0, _chunk7K3QN2ATjs.GenericUserSession)(clientStorage);
58
58
  userSession.set(null);
59
59
  });
60
- var NextjsCookieStorage = class extends _chunkO6DPCPRHjs.CookieStorage {
60
+ var NextjsCookieStorage = class extends _chunk6RFRDWIPjs.CookieStorage {
61
61
  constructor(config = {}) {
62
62
  super({
63
63
  secure: true,
@@ -83,7 +83,7 @@ var NextjsCookieStorage = class extends _chunkO6DPCPRHjs.CookieStorage {
83
83
  _headersjs.cookies.call(void 0, ).set(key, value, cookieSettings);
84
84
  }
85
85
  };
86
- var NextjsClientStorage = class extends _chunkO6DPCPRHjs.CookieStorage {
86
+ var NextjsClientStorage = class extends _chunk6RFRDWIPjs.CookieStorage {
87
87
  constructor(config = {}) {
88
88
  super(_chunkCRTRMMJ7js.__spreadProps.call(void 0, _chunkCRTRMMJ7js.__spreadValues.call(void 0, {}, config), {
89
89
  secure: false,
@@ -115,4 +115,4 @@ var resolveCallbackUrl = (config, alternativeUrl) => {
115
115
 
116
116
 
117
117
  exports.createTokenCookies = createTokenCookies; exports.createUserInfoCookie = createUserInfoCookie; exports.clearAuthCookies = clearAuthCookies; exports.NextjsCookieStorage = NextjsCookieStorage; exports.NextjsClientStorage = NextjsClientStorage; exports.resolveCallbackUrl = resolveCallbackUrl;
118
- //# sourceMappingURL=chunk-DJFTZS4P.js.map
118
+ //# sourceMappingURL=chunk-CTVJJBBA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-CTVJJBBA.js","../src/nextjs/cookies.ts","../src/nextjs/utils.ts"],"names":[],"mappings":"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","file":"/Users/flippie/civic/repos/civic-auth/packages/civic-auth-client/dist/chunk-CTVJJBBA.js","sourcesContent":[null,"import { SessionData, UnknownObject, User } from \"@/types\";\nimport { NextResponse } from \"next/server\";\nimport { AuthConfig } from \"@/nextjs/config\";\nimport { CookieStorage, CookieStorageSettings } from \"@/server\";\nimport { cookies } from \"next/headers.js\";\nimport { GenericUserSession } from \"@/shared/UserSession\";\nimport { clearTokens } from \"@/shared/util\";\nimport { CodeVerifier, OAuthTokens, TokensCookieConfig } from \"@/shared/types\";\n\n/**\n * Creates HTTP-only cookies for authentication tokens\n */\nconst createTokenCookies = (\n response: NextResponse,\n sessionData: SessionData,\n config: AuthConfig,\n) => {\n const maxAge = sessionData.expiresIn ?? 3600;\n const cookieOptions = {\n ...config.cookies?.tokens,\n maxAge,\n };\n\n if (sessionData.accessToken) {\n response.cookies.set(\"access_token\", sessionData.accessToken, {\n ...cookieOptions,\n httpOnly: true,\n });\n }\n\n if (sessionData.idToken) {\n response.cookies.set(\"id_token\", sessionData.idToken, {\n ...cookieOptions,\n httpOnly: true,\n });\n }\n\n if (sessionData.refreshToken) {\n response.cookies.set(\"refresh_token\", sessionData.refreshToken, {\n ...cookieOptions,\n httpOnly: true,\n });\n }\n};\n\n/**\n * Creates a client-readable cookie with user info\n */\nconst createUserInfoCookie = (\n response: NextResponse,\n user: User<UnknownObject> | null,\n sessionData: SessionData,\n config: AuthConfig,\n) => {\n if (!user) {\n response.cookies.set(\"user\", \"\", {\n ...config.cookies?.user,\n maxAge: 0,\n });\n return;\n }\n const maxAge = sessionData.expiresIn ?? 3600;\n\n // TODO select fields to include in the user cookie\n const frontendUser = {\n ...user,\n };\n\n // TODO make call to get user info from the\n // auth server /userinfo endpoint when it's available\n // then add to the default claims above\n\n response.cookies.set(\"user\", JSON.stringify(frontendUser), {\n ...config.cookies?.user,\n maxAge,\n });\n};\n\n/**\n * Clears all authentication cookies\n */\nconst clearAuthCookies = async (config: AuthConfig) => {\n // clear session, and tokens\n const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens);\n clearTokens(cookieStorage);\n\n // clear user\n const clientStorage = new NextjsClientStorage();\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(null);\n};\n\ntype KeySetter = OAuthTokens | CodeVerifier;\nclass NextjsCookieStorage extends CookieStorage {\n constructor(readonly config: Partial<TokensCookieConfig> = {}) {\n super({\n secure: true,\n httpOnly: true,\n });\n }\n\n get(key: string): string | null {\n return cookies().get(key)?.value || null;\n }\n\n set(key: KeySetter, value: string): void {\n const cookieSettings = this.config?.[key as KeySetter] || {\n ...this.settings,\n };\n console.log(\n \"NextjsCookieStorage.set\",\n JSON.stringify(\n { key, value, config: this.config, cookieSettings },\n null,\n 2,\n ),\n );\n cookies().set(key, value, cookieSettings);\n }\n}\n\nclass NextjsClientStorage extends CookieStorage {\n constructor(config: Partial<CookieStorageSettings> = {}) {\n super({\n ...config,\n secure: false,\n httpOnly: false,\n });\n }\n\n get(key: string): string | null {\n return cookies().get(key)?.value || null;\n }\n\n set(key: string, value: string): void {\n cookies().set(key, value, this.settings);\n }\n}\n\nexport {\n createTokenCookies,\n createUserInfoCookie,\n clearAuthCookies,\n NextjsCookieStorage,\n NextjsClientStorage,\n};\n","import { AuthConfigWithDefaults } from \"@/nextjs/config\";\n\nexport const resolveCallbackUrl = (\n config: AuthConfigWithDefaults,\n alternativeUrl?: string,\n): string => {\n const baseUrl = config.appUrl ?? alternativeUrl;\n const callbackUrl = new URL(config?.callbackUrl, baseUrl).toString();\n return callbackUrl.toString();\n};\n"]}