@civic/auth 0.6.0-beta.2 → 0.6.0

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 (68) hide show
  1. package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
  2. package/dist/shared/hooks/useSignIn.js +8 -0
  3. package/dist/shared/hooks/useSignIn.js.map +1 -1
  4. package/dist/shared/version.d.ts +1 -1
  5. package/dist/shared/version.d.ts.map +1 -1
  6. package/dist/shared/version.js +1 -1
  7. package/dist/shared/version.js.map +1 -1
  8. package/dist/vanillajs/auth/AuthenticationEvents.d.ts +11 -0
  9. package/dist/vanillajs/auth/AuthenticationEvents.d.ts.map +1 -0
  10. package/dist/vanillajs/auth/AuthenticationEvents.js +36 -0
  11. package/dist/vanillajs/auth/AuthenticationEvents.js.map +1 -0
  12. package/dist/vanillajs/auth/CivicAuth.d.ts +147 -0
  13. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -0
  14. package/dist/vanillajs/auth/CivicAuth.js +513 -0
  15. package/dist/vanillajs/auth/CivicAuth.js.map +1 -0
  16. package/dist/vanillajs/auth/SessionManager.d.ts +17 -0
  17. package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -0
  18. package/dist/vanillajs/auth/SessionManager.js +86 -0
  19. package/dist/vanillajs/auth/SessionManager.js.map +1 -0
  20. package/dist/vanillajs/iframe/SignalObserver.d.ts +33 -0
  21. package/dist/vanillajs/iframe/SignalObserver.d.ts.map +1 -0
  22. package/dist/vanillajs/iframe/SignalObserver.js +162 -0
  23. package/dist/vanillajs/iframe/SignalObserver.js.map +1 -0
  24. package/dist/vanillajs/iframe/domUtils.d.ts +4 -0
  25. package/dist/vanillajs/iframe/domUtils.d.ts.map +1 -0
  26. package/dist/vanillajs/iframe/domUtils.js +25 -0
  27. package/dist/vanillajs/iframe/domUtils.js.map +1 -0
  28. package/dist/vanillajs/index.d.ts +16 -0
  29. package/dist/vanillajs/index.d.ts.map +1 -0
  30. package/dist/vanillajs/index.js +15 -0
  31. package/dist/vanillajs/index.js.map +1 -0
  32. package/dist/vanillajs/services/ApiService.d.ts +22 -0
  33. package/dist/vanillajs/services/ApiService.d.ts.map +1 -0
  34. package/dist/vanillajs/services/ApiService.js +82 -0
  35. package/dist/vanillajs/services/ApiService.js.map +1 -0
  36. package/dist/vanillajs/storage/BrowserCookieStorageAdapter.d.ts +19 -0
  37. package/dist/vanillajs/storage/BrowserCookieStorageAdapter.d.ts.map +1 -0
  38. package/dist/vanillajs/storage/BrowserCookieStorageAdapter.js +101 -0
  39. package/dist/vanillajs/storage/BrowserCookieStorageAdapter.js.map +1 -0
  40. package/dist/vanillajs/storage/BrowserLocalStorageAdapter.d.ts +9 -0
  41. package/dist/vanillajs/storage/BrowserLocalStorageAdapter.d.ts.map +1 -0
  42. package/dist/vanillajs/storage/BrowserLocalStorageAdapter.js +36 -0
  43. package/dist/vanillajs/storage/BrowserLocalStorageAdapter.js.map +1 -0
  44. package/dist/vanillajs/storage/InMemoryStorageAdapter.d.ts +9 -0
  45. package/dist/vanillajs/storage/InMemoryStorageAdapter.d.ts.map +1 -0
  46. package/dist/vanillajs/storage/InMemoryStorageAdapter.js +16 -0
  47. package/dist/vanillajs/storage/InMemoryStorageAdapter.js.map +1 -0
  48. package/dist/vanillajs/storage/StorageAdapter.d.ts +15 -0
  49. package/dist/vanillajs/storage/StorageAdapter.d.ts.map +1 -0
  50. package/dist/vanillajs/storage/StorageAdapter.js +16 -0
  51. package/dist/vanillajs/storage/StorageAdapter.js.map +1 -0
  52. package/dist/vanillajs/types/index.d.ts +28 -0
  53. package/dist/vanillajs/types/index.d.ts.map +1 -0
  54. package/dist/vanillajs/types/index.js +14 -0
  55. package/dist/vanillajs/types/index.js.map +1 -0
  56. package/dist/vanillajs/utils/auth-utils.d.ts +13 -0
  57. package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -0
  58. package/dist/vanillajs/utils/auth-utils.js +15 -0
  59. package/dist/vanillajs/utils/auth-utils.js.map +1 -0
  60. package/dist/vanillajs/utils/logger.d.ts +29 -0
  61. package/dist/vanillajs/utils/logger.d.ts.map +1 -0
  62. package/dist/vanillajs/utils/logger.js +62 -0
  63. package/dist/vanillajs/utils/logger.js.map +1 -0
  64. package/dist/vanillajs/utils/page-handlers.d.ts +29 -0
  65. package/dist/vanillajs/utils/page-handlers.d.ts.map +1 -0
  66. package/dist/vanillajs/utils/page-handlers.js +165 -0
  67. package/dist/vanillajs/utils/page-handlers.js.map +1 -0
  68. package/package.json +1 -1
@@ -0,0 +1,165 @@
1
+ import { exchangeTokens, buildOauth2Client, getEndpointsWithOverrides, getCookiesMaxAge, } from "../../shared/lib/util.js";
2
+ import { OAuthTokenTypes, CodeVerifier } from "../../shared/lib/types.js";
3
+ import { BrowserCookieStorageAdapter } from "../storage/BrowserCookieStorageAdapter.js";
4
+ import { getCurrentLogger } from "./logger.js";
5
+ import { GenericPublicClientPKCEProducer } from "../../services/PKCE.js";
6
+ // Default cookie configuration
7
+ const defaultCookiesMaxAge = 60 * 60; // 1 hour
8
+ const defaultCookieOptions = {
9
+ secure: true,
10
+ httpOnly: false,
11
+ sameSite: "lax", // Added type for sameSite
12
+ path: "/",
13
+ maxAge: defaultCookiesMaxAge,
14
+ };
15
+ const cookieConfig = {
16
+ tokens: {
17
+ [OAuthTokenTypes.ID_TOKEN]: { ...defaultCookieOptions },
18
+ [OAuthTokenTypes.ACCESS_TOKEN]: { ...defaultCookieOptions },
19
+ [OAuthTokenTypes.REFRESH_TOKEN]: { ...defaultCookieOptions },
20
+ [OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT]: {
21
+ ...defaultCookieOptions,
22
+ httpOnly: false,
23
+ },
24
+ [CodeVerifier.COOKIE_NAME]: { ...defaultCookieOptions, httpOnly: true },
25
+ [CodeVerifier.APP_URL]: { ...defaultCookieOptions, httpOnly: true },
26
+ },
27
+ user: {
28
+ ...defaultCookieOptions,
29
+ httpOnly: false,
30
+ },
31
+ };
32
+ export async function storeTokens(tokens, storageAdapter,
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ customCookieConfig, loggerInstance = getCurrentLogger()) {
35
+ const { accessTokenMaxAge, refreshTokenMaxAge } = getCookiesMaxAge(tokens);
36
+ let userInfoForReturn = null; // To store userInfo for returning
37
+ const idTokenCookieOpts = customCookieConfig?.tokens?.[OAuthTokenTypes.ID_TOKEN] ??
38
+ cookieConfig.tokens[OAuthTokenTypes.ID_TOKEN];
39
+ await storageAdapter.setItem(OAuthTokenTypes.ID_TOKEN, tokens.id_token, {
40
+ ...idTokenCookieOpts,
41
+ maxAge: accessTokenMaxAge,
42
+ });
43
+ const accessTokenValue = tokens.access_token || "";
44
+ const accessTokenCookieOpts = customCookieConfig?.tokens?.[OAuthTokenTypes.ACCESS_TOKEN] ??
45
+ cookieConfig.tokens[OAuthTokenTypes.ACCESS_TOKEN];
46
+ await storageAdapter.setItem(OAuthTokenTypes.ACCESS_TOKEN, accessTokenValue, {
47
+ ...accessTokenCookieOpts,
48
+ maxAge: accessTokenMaxAge,
49
+ });
50
+ if (tokens.refresh_token) {
51
+ const refreshTokenCookieOpts = customCookieConfig?.tokens?.[OAuthTokenTypes.REFRESH_TOKEN] ??
52
+ cookieConfig.tokens[OAuthTokenTypes.REFRESH_TOKEN];
53
+ await storageAdapter.setItem(OAuthTokenTypes.REFRESH_TOKEN, tokens.refresh_token, {
54
+ ...refreshTokenCookieOpts,
55
+ maxAge: refreshTokenMaxAge,
56
+ });
57
+ }
58
+ if (tokens.expires_in) {
59
+ const expiresAt = Math.floor(Date.now() / 1000) + tokens.expires_in;
60
+ const expiresAtCookieOpts = customCookieConfig?.tokens?.[OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT] ??
61
+ cookieConfig.tokens[OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT];
62
+ await storageAdapter.setItem(OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT, String(expiresAt), {
63
+ ...expiresAtCookieOpts,
64
+ maxAge: accessTokenMaxAge,
65
+ });
66
+ }
67
+ try {
68
+ if (typeof tokens.id_token === "string") {
69
+ const parts = tokens.id_token.split(".");
70
+ if (parts.length === 3) {
71
+ const idTokenPayload = JSON.parse(atob(parts[1]));
72
+ const userInfo = {
73
+ name: idTokenPayload.name,
74
+ picture: idTokenPayload.picture,
75
+ email: idTokenPayload.email,
76
+ id: idTokenPayload.sub,
77
+ };
78
+ userInfoForReturn = userInfo; // Assign for returning
79
+ const encodedUserInfo = encodeURIComponent(JSON.stringify(userInfo));
80
+ const userCookieOpts = customCookieConfig?.user ?? cookieConfig.user;
81
+ await storageAdapter.setItem("user", encodedUserInfo, {
82
+ ...userCookieOpts,
83
+ maxAge: accessTokenMaxAge,
84
+ });
85
+ loggerInstance.info("CivicAuth: User info stored successfully from id_token.");
86
+ }
87
+ else {
88
+ loggerInstance.warn("CivicAuth: Error storing user info - id_token does not have the expected JWT structure (header.payload.signature).");
89
+ userInfoForReturn = null;
90
+ }
91
+ }
92
+ else {
93
+ loggerInstance.warn("CivicAuth: Error storing user info - id_token is missing or not a string.");
94
+ userInfoForReturn = null;
95
+ }
96
+ }
97
+ catch (error) {
98
+ loggerInstance.error("CivicAuth: Error processing or storing user info from id_token:", error);
99
+ userInfoForReturn = null;
100
+ }
101
+ return userInfoForReturn; // Return the user info object or null
102
+ }
103
+ /**
104
+ * Adapter to convert BrowserCookieStorageAdapter to AuthStorage interface
105
+ */
106
+ class CookieStorageToAuthStorage {
107
+ storage;
108
+ constructor(storage) {
109
+ this.storage = storage;
110
+ }
111
+ async get(key) {
112
+ return this.storage.getItem(key);
113
+ }
114
+ async set(key, value) {
115
+ await this.storage.setItem(key, value);
116
+ }
117
+ async delete(key) {
118
+ await this.storage.removeItem(key);
119
+ }
120
+ }
121
+ export async function handleOAuthRedirectPage(config) {
122
+ const loggerInstance = config.logger || getCurrentLogger();
123
+ const urlParams = new URLSearchParams(window.location.search);
124
+ const code = urlParams.get("code");
125
+ const state = urlParams.get("state");
126
+ if (code && state) {
127
+ loggerInstance.info("CivicAuth: OAuth callback detected with code:", code);
128
+ const storage = config.storageAdapter || new BrowserCookieStorageAdapter();
129
+ const authStorage = new CookieStorageToAuthStorage(storage);
130
+ const pkceProducer = new GenericPublicClientPKCEProducer(authStorage);
131
+ try {
132
+ const endpoints = await getEndpointsWithOverrides(config.oauthServer);
133
+ const oauth2Client = buildOauth2Client(config.clientId, config.redirectUrl, endpoints);
134
+ const tokenResponse = await exchangeTokens(code, state, pkceProducer, oauth2Client, config.oauthServer, endpoints);
135
+ // Get userInfo from storeTokens
136
+ const userInfo = await storeTokens(tokenResponse, storage, config.cookieOptions, loggerInstance);
137
+ loggerInstance.info("CivicAuth: Tokens stored successfully.");
138
+ const signalElement = document.createElement("div");
139
+ signalElement.id = "civic-auth-success-signal";
140
+ signalElement.textContent = config.textSignals.success;
141
+ if (userInfo) {
142
+ // Embed userInfo if available
143
+ signalElement.setAttribute("data-user-info", JSON.stringify(userInfo));
144
+ }
145
+ signalElement.style.display = "none";
146
+ document.body.appendChild(signalElement);
147
+ loggerInstance.info("CivicAuth: Appended success signal to body.");
148
+ // Clean up the code verifier
149
+ await authStorage.delete(CodeVerifier.COOKIE_NAME);
150
+ }
151
+ catch (error) {
152
+ loggerInstance.error("CivicAuth: Token exchange error:", error);
153
+ const errorSignalElement = document.createElement("div");
154
+ errorSignalElement.id = "civic-auth-error-signal";
155
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
156
+ errorSignalElement.textContent = `${config.textSignals.error} (Error: ${errorMessage})`;
157
+ errorSignalElement.style.display = "none";
158
+ document.body.appendChild(errorSignalElement);
159
+ return true;
160
+ }
161
+ return true;
162
+ }
163
+ return false;
164
+ }
165
+ //# sourceMappingURL=page-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-handlers.js","sourceRoot":"","sources":["../../../src/vanillajs/utils/page-handlers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n exchangeTokens,\n buildOauth2Client,\n getEndpointsWithOverrides,\n getCookiesMaxAge,\n} from \"../../shared/lib/util.js\";\nimport { OAuthTokenTypes, CodeVerifier } from \"../../shared/lib/types.js\";\nimport { BrowserCookieStorageAdapter } from \"../storage/BrowserCookieStorageAdapter.js\";\nimport { getCurrentLogger } from \"./logger.js\";\nimport { GenericPublicClientPKCEProducer } from \"../../services/PKCE.js\";\nimport type { AuthStorage } from \"../../types.js\";\n\n// Types\ninterface ExchangeTokenResponse {\n id_token: string; // Required readonly string\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n}\n\n// Default cookie configuration\nconst defaultCookiesMaxAge = 60 * 60; // 1 hour\nconst defaultCookieOptions = {\n secure: true,\n httpOnly: false,\n sameSite: \"lax\" as \"lax\" | \"strict\" | \"none\", // Added type for sameSite\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n};\n\nconst cookieConfig = {\n tokens: {\n [OAuthTokenTypes.ID_TOKEN]: { ...defaultCookieOptions },\n [OAuthTokenTypes.ACCESS_TOKEN]: { ...defaultCookieOptions },\n [OAuthTokenTypes.REFRESH_TOKEN]: { ...defaultCookieOptions },\n [OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT]: {\n ...defaultCookieOptions,\n httpOnly: false,\n },\n [CodeVerifier.COOKIE_NAME]: { ...defaultCookieOptions, httpOnly: true },\n [CodeVerifier.APP_URL]: { ...defaultCookieOptions, httpOnly: true },\n },\n user: {\n ...defaultCookieOptions,\n httpOnly: false,\n },\n};\n\nexport async function storeTokens(\n tokens: ExchangeTokenResponse,\n storageAdapter: BrowserCookieStorageAdapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n customCookieConfig?: any,\n loggerInstance = getCurrentLogger(),\n): Promise<object | null> {\n const { accessTokenMaxAge, refreshTokenMaxAge } = getCookiesMaxAge(tokens);\n let userInfoForReturn: object | null = null; // To store userInfo for returning\n\n const idTokenCookieOpts =\n customCookieConfig?.tokens?.[OAuthTokenTypes.ID_TOKEN] ??\n cookieConfig.tokens[OAuthTokenTypes.ID_TOKEN];\n await storageAdapter.setItem(OAuthTokenTypes.ID_TOKEN, tokens.id_token, {\n ...idTokenCookieOpts,\n maxAge: accessTokenMaxAge,\n });\n\n const accessTokenValue = tokens.access_token || \"\";\n const accessTokenCookieOpts =\n customCookieConfig?.tokens?.[OAuthTokenTypes.ACCESS_TOKEN] ??\n cookieConfig.tokens[OAuthTokenTypes.ACCESS_TOKEN];\n await storageAdapter.setItem(OAuthTokenTypes.ACCESS_TOKEN, accessTokenValue, {\n ...accessTokenCookieOpts,\n maxAge: accessTokenMaxAge,\n });\n\n if (tokens.refresh_token) {\n const refreshTokenCookieOpts =\n customCookieConfig?.tokens?.[OAuthTokenTypes.REFRESH_TOKEN] ??\n cookieConfig.tokens[OAuthTokenTypes.REFRESH_TOKEN];\n await storageAdapter.setItem(\n OAuthTokenTypes.REFRESH_TOKEN,\n tokens.refresh_token,\n {\n ...refreshTokenCookieOpts,\n maxAge: refreshTokenMaxAge,\n },\n );\n }\n\n if (tokens.expires_in) {\n const expiresAt = Math.floor(Date.now() / 1000) + tokens.expires_in;\n const expiresAtCookieOpts =\n customCookieConfig?.tokens?.[OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT] ??\n cookieConfig.tokens[OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT];\n await storageAdapter.setItem(\n OAuthTokenTypes.ACCESS_TOKEN_EXPIRES_AT,\n String(expiresAt),\n {\n ...expiresAtCookieOpts,\n maxAge: accessTokenMaxAge,\n },\n );\n }\n\n try {\n if (typeof tokens.id_token === \"string\") {\n const parts = tokens.id_token.split(\".\");\n if (parts.length === 3) {\n const idTokenPayload = JSON.parse(atob(parts[1]!));\n const userInfo = {\n name: idTokenPayload.name,\n picture: idTokenPayload.picture,\n email: idTokenPayload.email,\n id: idTokenPayload.sub,\n };\n userInfoForReturn = userInfo; // Assign for returning\n const encodedUserInfo = encodeURIComponent(JSON.stringify(userInfo));\n const userCookieOpts = customCookieConfig?.user ?? cookieConfig.user;\n await storageAdapter.setItem(\"user\", encodedUserInfo, {\n ...userCookieOpts,\n maxAge: accessTokenMaxAge,\n });\n loggerInstance.info(\n \"CivicAuth: User info stored successfully from id_token.\",\n );\n } else {\n loggerInstance.warn(\n \"CivicAuth: Error storing user info - id_token does not have the expected JWT structure (header.payload.signature).\",\n );\n userInfoForReturn = null;\n }\n } else {\n loggerInstance.warn(\n \"CivicAuth: Error storing user info - id_token is missing or not a string.\",\n );\n userInfoForReturn = null;\n }\n } catch (error) {\n loggerInstance.error(\n \"CivicAuth: Error processing or storing user info from id_token:\",\n error,\n );\n userInfoForReturn = null;\n }\n return userInfoForReturn; // Return the user info object or null\n}\n\nexport interface HandleOAuthRedirectConfig {\n clientId: string;\n redirectUrl: string;\n oauthServer: string;\n textSignals: {\n success: string;\n error: string;\n };\n storageAdapter?: BrowserCookieStorageAdapter;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cookieOptions?: any; // To pass custom cookie configurations if needed\n logger?: ReturnType<typeof getCurrentLogger>;\n}\n\n/**\n * Adapter to convert BrowserCookieStorageAdapter to AuthStorage interface\n */\nclass CookieStorageToAuthStorage implements AuthStorage {\n constructor(private storage: BrowserCookieStorageAdapter) {}\n\n async get(key: string): Promise<string | null> {\n return this.storage.getItem(key);\n }\n\n async set(key: string, value: string): Promise<void> {\n await this.storage.setItem(key, value);\n }\n\n async delete(key: string): Promise<void> {\n await this.storage.removeItem(key);\n }\n}\n\nexport async function handleOAuthRedirectPage(\n config: HandleOAuthRedirectConfig,\n): Promise<boolean> {\n const loggerInstance = config.logger || getCurrentLogger();\n const urlParams = new URLSearchParams(window.location.search);\n const code = urlParams.get(\"code\");\n const state = urlParams.get(\"state\");\n\n if (code && state) {\n loggerInstance.info(\"CivicAuth: OAuth callback detected with code:\", code);\n\n const storage = config.storageAdapter || new BrowserCookieStorageAdapter();\n const authStorage = new CookieStorageToAuthStorage(storage);\n const pkceProducer = new GenericPublicClientPKCEProducer(authStorage);\n\n try {\n const endpoints = await getEndpointsWithOverrides(config.oauthServer);\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n\n const tokenResponse = await exchangeTokens(\n code,\n state,\n pkceProducer,\n oauth2Client,\n config.oauthServer,\n endpoints,\n );\n\n // Get userInfo from storeTokens\n const userInfo = await storeTokens(\n tokenResponse,\n storage,\n config.cookieOptions,\n loggerInstance,\n );\n loggerInstance.info(\"CivicAuth: Tokens stored successfully.\");\n\n const signalElement = document.createElement(\"div\");\n signalElement.id = \"civic-auth-success-signal\";\n signalElement.textContent = config.textSignals.success;\n if (userInfo) {\n // Embed userInfo if available\n signalElement.setAttribute(\"data-user-info\", JSON.stringify(userInfo));\n }\n signalElement.style.display = \"none\";\n document.body.appendChild(signalElement);\n loggerInstance.info(\"CivicAuth: Appended success signal to body.\");\n\n // Clean up the code verifier\n await authStorage.delete(CodeVerifier.COOKIE_NAME);\n } catch (error) {\n loggerInstance.error(\"CivicAuth: Token exchange error:\", error);\n const errorSignalElement = document.createElement(\"div\");\n errorSignalElement.id = \"civic-auth-error-signal\";\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown error\";\n errorSignalElement.textContent = `${config.textSignals.error} (Error: ${errorMessage})`;\n errorSignalElement.style.display = \"none\";\n document.body.appendChild(errorSignalElement);\n return true;\n }\n return true;\n }\n return false;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civic/auth",
3
- "version": "0.6.0-beta.2",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",