@civic/auth 0.0.1-tsc.alpha.3 → 0.1.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 (155) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/.turbo/turbo-lint.log +2 -9
  3. package/.turbo/turbo-test.log +396 -474
  4. package/CHANGELOG.md +2 -0
  5. package/dist/cjs/src/browser/storage.d.ts +2 -2
  6. package/dist/cjs/src/browser/storage.d.ts.map +1 -1
  7. package/dist/cjs/src/browser/storage.js +3 -3
  8. package/dist/cjs/src/browser/storage.js.map +1 -1
  9. package/dist/cjs/src/nextjs/GetUser.d.ts +1 -1
  10. package/dist/cjs/src/nextjs/GetUser.d.ts.map +1 -1
  11. package/dist/cjs/src/nextjs/GetUser.js +3 -3
  12. package/dist/cjs/src/nextjs/GetUser.js.map +1 -1
  13. package/dist/cjs/src/nextjs/config.d.ts.map +1 -1
  14. package/dist/cjs/src/nextjs/config.js +0 -2
  15. package/dist/cjs/src/nextjs/config.js.map +1 -1
  16. package/dist/cjs/src/nextjs/cookies.d.ts +4 -4
  17. package/dist/cjs/src/nextjs/cookies.d.ts.map +1 -1
  18. package/dist/cjs/src/nextjs/cookies.js +14 -11
  19. package/dist/cjs/src/nextjs/cookies.js.map +1 -1
  20. package/dist/cjs/src/nextjs/index.d.ts +1 -1
  21. package/dist/cjs/src/nextjs/index.d.ts.map +1 -1
  22. package/dist/cjs/src/nextjs/index.js.map +1 -1
  23. package/dist/cjs/src/nextjs/routeHandler.d.ts.map +1 -1
  24. package/dist/cjs/src/nextjs/routeHandler.js +1 -5
  25. package/dist/cjs/src/nextjs/routeHandler.js.map +1 -1
  26. package/dist/cjs/src/reactjs/hooks/index.d.ts +0 -1
  27. package/dist/cjs/src/reactjs/hooks/index.d.ts.map +1 -1
  28. package/dist/cjs/src/reactjs/hooks/index.js +1 -3
  29. package/dist/cjs/src/reactjs/hooks/index.js.map +1 -1
  30. package/dist/cjs/src/server/ServerAuthenticationResolver.d.ts.map +1 -1
  31. package/dist/cjs/src/server/ServerAuthenticationResolver.js +2 -7
  32. package/dist/cjs/src/server/ServerAuthenticationResolver.js.map +1 -1
  33. package/dist/cjs/src/server/login.d.ts +2 -2
  34. package/dist/cjs/src/server/login.d.ts.map +1 -1
  35. package/dist/cjs/src/server/login.js +2 -2
  36. package/dist/cjs/src/server/login.js.map +1 -1
  37. package/dist/cjs/src/services/AuthenticationService.d.ts.map +1 -1
  38. package/dist/cjs/src/services/AuthenticationService.js +6 -16
  39. package/dist/cjs/src/services/AuthenticationService.js.map +1 -1
  40. package/dist/cjs/src/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
  41. package/dist/cjs/src/shared/components/CivicAuthIframeContainer.js +0 -2
  42. package/dist/cjs/src/shared/components/CivicAuthIframeContainer.js.map +1 -1
  43. package/dist/cjs/src/shared/components/LoadingIcon.d.ts.map +1 -1
  44. package/dist/cjs/src/shared/components/LoadingIcon.js +6 -0
  45. package/dist/cjs/src/shared/components/LoadingIcon.js.map +1 -1
  46. package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
  47. package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.js +2 -6
  48. package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
  49. package/dist/cjs/src/shared/lib/UserSession.d.ts +4 -4
  50. package/dist/cjs/src/shared/lib/UserSession.d.ts.map +1 -1
  51. package/dist/cjs/src/shared/lib/UserSession.js +4 -4
  52. package/dist/cjs/src/shared/lib/UserSession.js.map +1 -1
  53. package/dist/cjs/src/shared/lib/session.js +1 -1
  54. package/dist/cjs/src/shared/lib/session.js.map +1 -1
  55. package/dist/cjs/src/shared/lib/storage.d.ts +2 -2
  56. package/dist/cjs/src/shared/lib/storage.d.ts.map +1 -1
  57. package/dist/cjs/src/shared/lib/storage.js.map +1 -1
  58. package/dist/cjs/src/shared/lib/util.d.ts +4 -4
  59. package/dist/cjs/src/shared/lib/util.d.ts.map +1 -1
  60. package/dist/cjs/src/shared/lib/util.js +16 -15
  61. package/dist/cjs/src/shared/lib/util.js.map +1 -1
  62. package/dist/cjs/src/types.d.ts +2 -2
  63. package/dist/cjs/src/types.d.ts.map +1 -1
  64. package/dist/cjs/src/types.js.map +1 -1
  65. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  66. package/dist/esm/src/browser/storage.d.ts +2 -2
  67. package/dist/esm/src/browser/storage.d.ts.map +1 -1
  68. package/dist/esm/src/browser/storage.js +3 -3
  69. package/dist/esm/src/browser/storage.js.map +1 -1
  70. package/dist/esm/src/nextjs/GetUser.d.ts +1 -1
  71. package/dist/esm/src/nextjs/GetUser.d.ts.map +1 -1
  72. package/dist/esm/src/nextjs/GetUser.js +3 -3
  73. package/dist/esm/src/nextjs/GetUser.js.map +1 -1
  74. package/dist/esm/src/nextjs/config.d.ts.map +1 -1
  75. package/dist/esm/src/nextjs/config.js +0 -2
  76. package/dist/esm/src/nextjs/config.js.map +1 -1
  77. package/dist/esm/src/nextjs/cookies.d.ts +4 -4
  78. package/dist/esm/src/nextjs/cookies.d.ts.map +1 -1
  79. package/dist/esm/src/nextjs/cookies.js +14 -11
  80. package/dist/esm/src/nextjs/cookies.js.map +1 -1
  81. package/dist/esm/src/nextjs/index.d.ts +1 -1
  82. package/dist/esm/src/nextjs/index.d.ts.map +1 -1
  83. package/dist/esm/src/nextjs/index.js +1 -1
  84. package/dist/esm/src/nextjs/index.js.map +1 -1
  85. package/dist/esm/src/nextjs/routeHandler.d.ts.map +1 -1
  86. package/dist/esm/src/nextjs/routeHandler.js +1 -5
  87. package/dist/esm/src/nextjs/routeHandler.js.map +1 -1
  88. package/dist/esm/src/reactjs/hooks/index.d.ts +0 -1
  89. package/dist/esm/src/reactjs/hooks/index.d.ts.map +1 -1
  90. package/dist/esm/src/reactjs/hooks/index.js +0 -1
  91. package/dist/esm/src/reactjs/hooks/index.js.map +1 -1
  92. package/dist/esm/src/server/ServerAuthenticationResolver.d.ts.map +1 -1
  93. package/dist/esm/src/server/ServerAuthenticationResolver.js +2 -7
  94. package/dist/esm/src/server/ServerAuthenticationResolver.js.map +1 -1
  95. package/dist/esm/src/server/login.d.ts +2 -2
  96. package/dist/esm/src/server/login.d.ts.map +1 -1
  97. package/dist/esm/src/server/login.js +2 -2
  98. package/dist/esm/src/server/login.js.map +1 -1
  99. package/dist/esm/src/services/AuthenticationService.d.ts.map +1 -1
  100. package/dist/esm/src/services/AuthenticationService.js +6 -16
  101. package/dist/esm/src/services/AuthenticationService.js.map +1 -1
  102. package/dist/esm/src/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
  103. package/dist/esm/src/shared/components/CivicAuthIframeContainer.js +0 -2
  104. package/dist/esm/src/shared/components/CivicAuthIframeContainer.js.map +1 -1
  105. package/dist/esm/src/shared/components/LoadingIcon.d.ts.map +1 -1
  106. package/dist/esm/src/shared/components/LoadingIcon.js +6 -0
  107. package/dist/esm/src/shared/components/LoadingIcon.js.map +1 -1
  108. package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
  109. package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.js +2 -6
  110. package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
  111. package/dist/esm/src/shared/lib/UserSession.d.ts +4 -4
  112. package/dist/esm/src/shared/lib/UserSession.d.ts.map +1 -1
  113. package/dist/esm/src/shared/lib/UserSession.js +4 -4
  114. package/dist/esm/src/shared/lib/UserSession.js.map +1 -1
  115. package/dist/esm/src/shared/lib/session.js +1 -1
  116. package/dist/esm/src/shared/lib/session.js.map +1 -1
  117. package/dist/esm/src/shared/lib/storage.d.ts +2 -2
  118. package/dist/esm/src/shared/lib/storage.d.ts.map +1 -1
  119. package/dist/esm/src/shared/lib/storage.js.map +1 -1
  120. package/dist/esm/src/shared/lib/util.d.ts +4 -4
  121. package/dist/esm/src/shared/lib/util.d.ts.map +1 -1
  122. package/dist/esm/src/shared/lib/util.js +16 -15
  123. package/dist/esm/src/shared/lib/util.js.map +1 -1
  124. package/dist/esm/src/types.d.ts +2 -2
  125. package/dist/esm/src/types.d.ts.map +1 -1
  126. package/dist/esm/src/types.js.map +1 -1
  127. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  128. package/package.json +3 -3
  129. package/src/browser/storage.ts +3 -3
  130. package/src/nextjs/GetUser.ts +3 -3
  131. package/src/nextjs/config.ts +0 -2
  132. package/src/nextjs/cookies.ts +14 -18
  133. package/src/nextjs/index.ts +1 -3
  134. package/src/nextjs/routeHandler.ts +1 -5
  135. package/src/reactjs/hooks/index.ts +0 -1
  136. package/src/server/ServerAuthenticationResolver.ts +2 -7
  137. package/src/server/login.ts +8 -7
  138. package/src/services/AuthenticationService.ts +6 -16
  139. package/src/shared/components/CivicAuthIframeContainer.tsx +0 -4
  140. package/src/shared/components/LoadingIcon.tsx +8 -0
  141. package/src/shared/lib/GenericAuthenticationRefresher.ts +3 -8
  142. package/src/shared/lib/UserSession.ts +6 -6
  143. package/src/shared/lib/session.ts +1 -1
  144. package/src/shared/lib/storage.ts +2 -2
  145. package/src/shared/lib/util.ts +21 -18
  146. package/src/types.ts +2 -2
  147. package/test/unit/nextjs/getUser.test.ts +8 -8
  148. package/test/unit/publicApi/__snapshots__/apiSnapshot.test.ts.snap +0 -1
  149. package/test/unit/server/login.test.ts +20 -18
  150. package/test/unit/server/session.test.ts +4 -4
  151. package/test/unit/services/AuthenticationService.test.ts +3 -3
  152. package/test/unit/services/ServerAuthenticationResolver.test.ts +11 -6
  153. package/test/unit/shared/GenericAuthenticationRefresher.test.ts +4 -4
  154. package/test/unit/shared/UserSession.test.ts +6 -6
  155. package/test/unit/shared/storage.test.ts +6 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civic/auth",
3
- "version": "0.0.1-tsc.alpha.3",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "module": "dist/index.js",
6
6
  "main": "dist/index.ts",
@@ -99,10 +99,10 @@
99
99
  "build": "pnpm build:cjs && pnpm build:esm",
100
100
  "build:cjs": "tsc -p tsconfig.cjs.json --noEmit false && tsc-alias -p tsconfig.cjs.json",
101
101
  "build:esm": "tsc -p tsconfig.esm.json --noEmit false && tsc-alias -p tsconfig.esm.json",
102
- "prepublish": "pnpm build",
102
+ "prepublish": "node ../../etc/scripts/prompt-changelog.js && pnpm build",
103
103
  "dev": "tsc --watch",
104
104
  "test": "vitest",
105
- "lint": "eslint \"src/**/*.ts*\"",
105
+ "lint": "eslint \"src/**/*.ts*\" --max-warnings 0",
106
106
  "lint:fix": "pnpm lint --fix",
107
107
  "clean": "rm -rf .turbo dist node_modules",
108
108
  "test:update": "vitest --update"
@@ -1,11 +1,11 @@
1
1
  import type { AuthStorage } from "@/types.js";
2
2
 
3
3
  export class LocalStorageAdapter implements AuthStorage {
4
- get(key: string): string {
5
- return localStorage.getItem(key) || "";
4
+ async get(key: string): Promise<string> {
5
+ return Promise.resolve(localStorage.getItem(key) || "");
6
6
  }
7
7
 
8
- set(key: string, value: string): void {
8
+ async set(key: string, value: string): Promise<void> {
9
9
  localStorage.setItem(key, value);
10
10
  }
11
11
  }
@@ -6,11 +6,11 @@ import { GenericUserSession } from "@/shared/lib/UserSession.js";
6
6
  import { NextjsClientStorage } from "@/nextjs/cookies.js";
7
7
  import { retrieveTokens } from "@/shared/lib/util.js";
8
8
 
9
- export const getUser = (): User | null => {
9
+ export const getUser = async (): Promise<User | null> => {
10
10
  const clientStorage = new NextjsClientStorage();
11
11
  const userSession = new GenericUserSession(clientStorage);
12
- const tokens = retrieveTokens(clientStorage);
13
- const user = userSession.get();
12
+ const tokens = await retrieveTokens(clientStorage);
13
+ const user = await userSession.get();
14
14
  if (!user || !tokens) return null;
15
15
 
16
16
  return {
@@ -33,11 +33,9 @@ export type AuthConfig = Partial<AuthConfigWithDefaults>;
33
33
 
34
34
  export type DefinedAuthConfig = AuthConfigWithDefaults;
35
35
 
36
- console.log(`process.env.NODE_ENV: ${process.env.NODE_ENV}`);
37
36
  const isDevelopment = process.env.NODE_ENV === "development";
38
37
 
39
38
  const defaultServerSecure = isDevelopment ? false : true;
40
- console.log(`defaultServerSecure: ${defaultServerSecure}`);
41
39
  /**
42
40
  * Default configuration values that will be used if not overridden
43
41
  */
@@ -102,12 +102,12 @@ const createUserInfoCookie = (
102
102
  const clearAuthCookies = async (config: AuthConfig) => {
103
103
  // clear session, and tokens
104
104
  const cookieStorage = new NextjsCookieStorage(config.cookies?.tokens);
105
- clearTokens(cookieStorage);
105
+ await clearTokens(cookieStorage);
106
106
 
107
107
  // clear user
108
108
  const clientStorage = new NextjsClientStorage();
109
109
  const userSession = new GenericUserSession(clientStorage);
110
- userSession.set(null);
110
+ await userSession.set(null);
111
111
  };
112
112
 
113
113
  type KeySetter = OAuthTokens | CodeVerifier;
@@ -119,23 +119,17 @@ class NextjsCookieStorage extends CookieStorage {
119
119
  });
120
120
  }
121
121
 
122
- get(key: string): string | null {
123
- return cookies().get(key)?.value || null;
122
+ async get(key: string): Promise<string | null> {
123
+ const cookieStore = await cookies();
124
+ return cookieStore.get(key)?.value || null;
124
125
  }
125
126
 
126
- set(key: KeySetter, value: string): void {
127
+ async set(key: KeySetter, value: string): Promise<void> {
128
+ const cookieStore = await cookies();
127
129
  const cookieSettings = this.config?.[key as KeySetter] || {
128
130
  ...this.settings,
129
131
  };
130
- console.log(
131
- "NextjsCookieStorage.set",
132
- JSON.stringify(
133
- { key, value, config: this.config, cookieSettings },
134
- null,
135
- 2,
136
- ),
137
- );
138
- cookies().set(key, value, cookieSettings);
132
+ cookieStore.set(key, value, cookieSettings);
139
133
  }
140
134
  }
141
135
 
@@ -148,12 +142,14 @@ class NextjsClientStorage extends CookieStorage {
148
142
  });
149
143
  }
150
144
 
151
- get(key: string): string | null {
152
- return cookies().get(key)?.value || null;
145
+ async get(key: string): Promise<string | null> {
146
+ const cookieStore = await cookies();
147
+ return cookieStore.get(key)?.value || null;
153
148
  }
154
149
 
155
- set(key: string, value: string): void {
156
- cookies().set(key, value, this.settings);
150
+ async set(key: string, value: string): Promise<void> {
151
+ const cookieStore = await cookies();
152
+ cookieStore.set(key, value, this.settings);
157
153
  }
158
154
  }
159
155
 
@@ -1,6 +1,4 @@
1
- export {
2
- createCivicAuthPlugin,
3
- } from "@/nextjs/config.js";
1
+ export { createCivicAuthPlugin } from "@/nextjs/config.js";
4
2
  export { getUser } from "@/nextjs/GetUser.js";
5
3
  export { handler } from "@/nextjs/routeHandler.js";
6
4
  export {
@@ -19,7 +19,6 @@ import {
19
19
  TOKEN_EXCHANGE_TRIGGER_TEXT,
20
20
  } from "@/constants.js";
21
21
  import { serverTokenExchangeFromState } from "@/lib/oauth.js";
22
- import { cookies } from "next/headers.js";
23
22
  import { CodeVerifier } from "@/shared/lib/types.js";
24
23
 
25
24
  const logger = loggers.nextjs.handlers.auth;
@@ -108,7 +107,6 @@ async function handleCallback(
108
107
  console.log("handleCallback", {
109
108
  code,
110
109
  state,
111
- cookies: cookies(),
112
110
  appUrl,
113
111
  });
114
112
 
@@ -148,9 +146,7 @@ async function handleCallback(
148
146
  const appUrl = globalThis.window?.location?.origin;
149
147
  fetch('${fetchUrl}&appUrl=' + appUrl).then((response) => {
150
148
  response.json().then((jsonResponse) => {
151
- console.log('fetch jsonResponse', jsonResponse);
152
149
  if (jsonResponse.redirectUrl) {
153
- console.log('handleCallback serverTokenExchangeFromState, redirecting');
154
150
  window.location.href = jsonResponse.redirectUrl;
155
151
  }
156
152
  });
@@ -243,7 +239,7 @@ export async function handleLogout(
243
239
 
244
240
  const response = NextResponse.redirect(finalRedirectUrl);
245
241
 
246
- clearAuthCookies(config);
242
+ await clearAuthCookies(config);
247
243
 
248
244
  try {
249
245
  revalidatePath(isAbsoluteRedirect ? finalRedirectUrl : redirectTarget);
@@ -3,5 +3,4 @@ export { useToken } from "@/shared/hooks/useToken.js";
3
3
  export { useAuth } from "@/shared/hooks/useAuth.js";
4
4
  export { useSession } from "@/shared/hooks/useSession.js";
5
5
  export { useConfig } from "@/shared/hooks/useConfig.js";
6
- export { useTokenCookie } from "@/nextjs/hooks/useTokenCookie.js";
7
6
  export { useIframe } from "@/shared/hooks/useIframe.js";
@@ -25,11 +25,6 @@ export class ServerAuthenticationResolver implements AuthenticationResolver {
25
25
  readonly storage: AuthStorage,
26
26
  readonly endpointOverrides?: Partial<Endpoints>,
27
27
  ) {
28
- console.log("ServerAuthenticationResolver constructor", {
29
- authConfig,
30
- storage,
31
- endpointOverrides,
32
- });
33
28
  this.pkceProducer = new GenericPublicClientPKCEProducer(storage);
34
29
  }
35
30
  validateExistingSession(): Promise<SessionData> {
@@ -72,13 +67,13 @@ export class ServerAuthenticationResolver implements AuthenticationResolver {
72
67
  this.endpoints!, // clean up types here to avoid the ! operator
73
68
  );
74
69
 
75
- storeTokens(this.storage, tokens);
70
+ await storeTokens(this.storage, tokens);
76
71
 
77
72
  return tokens;
78
73
  }
79
74
 
80
75
  async getSessionData(): Promise<SessionData | null> {
81
- const storageData = retrieveTokens(this.storage);
76
+ const storageData = await retrieveTokens(this.storage);
82
77
 
83
78
  if (!storageData) return null;
84
79
 
@@ -29,16 +29,17 @@ export async function resolveOAuthAccessCode(
29
29
  return authSessionService.tokenExchange(code, state);
30
30
  }
31
31
 
32
- export function isLoggedIn(storage: AuthStorage): boolean {
33
- return !!storage.get("id_token");
32
+ export async function isLoggedIn(storage: AuthStorage): Promise<boolean> {
33
+ return !!(await storage.get("id_token"));
34
34
  }
35
35
 
36
36
  export async function buildLoginUrl(
37
- config: Pick<AuthConfig, "oauthServer" | "clientId" | "redirectUrl"> & {
38
- scopes?: string[];
39
- state?: string;
40
- nonce?: string;
41
- },
37
+ config: Pick<AuthConfig, "clientId" | "redirectUrl"> &
38
+ Partial<Pick<AuthConfig, "oauthServer">> & {
39
+ scopes?: string[];
40
+ state?: string;
41
+ nonce?: string;
42
+ },
42
43
  storage: AuthStorage,
43
44
  ): Promise<URL> {
44
45
  // generate a random state if not provided
@@ -74,7 +74,6 @@ export class BrowserAuthenticationInitiator implements AuthenticationInitiator {
74
74
 
75
75
  constructor(config: typeof this.config) {
76
76
  this.config = config;
77
- console.log("BrowserAuthenticationInitiator constructor", this.config);
78
77
  }
79
78
 
80
79
  async handleLoginAppPopupFailed(redirectUrl: string) {
@@ -97,11 +96,9 @@ export class BrowserAuthenticationInitiator implements AuthenticationInitiator {
97
96
  thisURL.hostname === "localhost"
98
97
  ) {
99
98
  if (!validateLoginAppPostMessage(event.data, this.config.clientId)) {
100
- console.log("Received invalid message from login app", event.data);
101
99
  return;
102
100
  }
103
101
  const loginMessage = event.data as LoginPostMessage;
104
- console.log("Received message from login app", event.data);
105
102
  this.handleLoginAppPopupFailed(loginMessage.data.url);
106
103
  }
107
104
  };
@@ -117,7 +114,6 @@ export class BrowserAuthenticationInitiator implements AuthenticationInitiator {
117
114
  if (this.config.displayMode === "new_tab") {
118
115
  try {
119
116
  const popupWindow = window.open(url.toString(), "_blank");
120
- console.log("signIn", popupWindow);
121
117
  if (!popupWindow) {
122
118
  throw new PopupError("Failed to open popup window");
123
119
  }
@@ -133,8 +129,8 @@ export class BrowserAuthenticationInitiator implements AuthenticationInitiator {
133
129
 
134
130
  async signOut(): Promise<URL> {
135
131
  const localStorage = new LocalStorageAdapter();
136
- clearTokens(localStorage);
137
- clearUser(localStorage);
132
+ await clearTokens(localStorage);
133
+ await clearUser(localStorage);
138
134
  // TODO open the iframe or new tab etc: the logout URL is not currently
139
135
  // supported by on the oauth, so just clear state until then
140
136
  const url = await generateOauthLogoutUrl(this.config);
@@ -168,9 +164,6 @@ export class GenericAuthenticationInitiator implements AuthenticationInitiator {
168
164
 
169
165
  constructor(config: typeof this.config) {
170
166
  this.config = config;
171
- console.log("GenericAuthenticationInitiator constructor", {
172
- config,
173
- });
174
167
  }
175
168
 
176
169
  // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url
@@ -207,9 +200,6 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
207
200
  // Since we are running fully on the client, we produce as well as consume the PKCE challenge
208
201
  protected pkceProducer = new BrowserPublicClientPKCEProducer(),
209
202
  ) {
210
- console.log("BrowserAuthenticationService constructor", {
211
- config,
212
- });
213
203
  super({
214
204
  ...config,
215
205
  state: generateState(config.displayMode),
@@ -260,7 +250,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
260
250
  this.endpoints!, // clean up types here to avoid the ! operator
261
251
  );
262
252
 
263
- storeTokens(new LocalStorageAdapter(), tokens);
253
+ await storeTokens(new LocalStorageAdapter(), tokens);
264
254
 
265
255
  // cleanup the browser window if needed
266
256
  const parsedDisplayMode = displayModeFromState(
@@ -279,7 +269,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
279
269
 
280
270
  // Get the session data from local storage
281
271
  async getSessionData(): Promise<SessionData | null> {
282
- const storageData = retrieveTokens(new LocalStorageAdapter());
272
+ const storageData = await retrieveTokens(new LocalStorageAdapter());
283
273
 
284
274
  if (!storageData) return null;
285
275
 
@@ -296,7 +286,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
296
286
  const sessionData = await this.getSessionData();
297
287
  if (!sessionData?.idToken || !sessionData.accessToken) {
298
288
  const unAuthenticatedSession = { ...sessionData, authenticated: false };
299
- clearTokens(new LocalStorageAdapter());
289
+ await clearTokens(new LocalStorageAdapter());
300
290
  return unAuthenticatedSession;
301
291
  }
302
292
  if (!this.endpoints || !this.oauth2client) await this.init();
@@ -318,7 +308,7 @@ export class BrowserAuthenticationService extends BrowserAuthenticationInitiator
318
308
  const unAuthenticatedSession = {
319
309
  authenticated: false,
320
310
  };
321
- clearTokens(new LocalStorageAdapter());
311
+ await clearTokens(new LocalStorageAdapter());
322
312
  return unAuthenticatedSession;
323
313
  }
324
314
  }
@@ -106,9 +106,6 @@ const CivicAuthIframeContainer = ({
106
106
  // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,
107
107
  // and we'll do the exchange request from here, which will include the cookies.
108
108
  if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {
109
- console.log(
110
- `${TOKEN_EXCHANGE_TRIGGER_TEXT}, calling callback URL again...`,
111
- );
112
109
  const params = new URL(iframeUrl).searchParams;
113
110
  const appUrl = globalThis.window?.location?.origin;
114
111
  fetch(
@@ -157,7 +154,6 @@ const CivicAuthIframeContainer = ({
157
154
 
158
155
  const handleIframeLoad = () => {
159
156
  setIsLoading(false);
160
- console.log("handleIframeLoad");
161
157
  if (processIframeUrl() && intervalId.current) {
162
158
  clearInterval(intervalId.current);
163
159
  }
@@ -2,6 +2,14 @@ import React from "react";
2
2
 
3
3
  const LoadingIcon = () => (
4
4
  <div role="status">
5
+ <style>
6
+ {`
7
+ @keyframes spin {
8
+ 0% { transform: rotate(0deg); }
9
+ 100% { transform: rotate(360deg); }
10
+ }
11
+ `}
12
+ </style>
5
13
  <svg
6
14
  aria-hidden="true"
7
15
  style={{
@@ -16,12 +16,7 @@ export class GenericAuthenticationRefresher implements AuthenticationRefresher {
16
16
  private authConfig: AuthConfig,
17
17
  private storage: AuthStorage,
18
18
  private endpointOverrides?: Partial<Endpoints>,
19
- ) {
20
- console.log("GenericAuthenticationRefresher constructor", {
21
- authConfig,
22
- endpointOverrides,
23
- });
24
- }
19
+ ) {}
25
20
 
26
21
  async init(): Promise<this> {
27
22
  // resolve oauth config
@@ -59,7 +54,7 @@ export class GenericAuthenticationRefresher implements AuthenticationRefresher {
59
54
  async refreshTokens() {
60
55
  if (!this.oauth2client) await this.init();
61
56
 
62
- const tokens = retrieveTokens(this.storage);
57
+ const tokens = await retrieveTokens(this.storage);
63
58
  if (!tokens?.refresh_token) throw new Error("No refresh token available");
64
59
 
65
60
  const oauth2Client = this.oauth2client!;
@@ -68,7 +63,7 @@ export class GenericAuthenticationRefresher implements AuthenticationRefresher {
68
63
  tokens.refresh_token,
69
64
  );
70
65
 
71
- storeTokens(this.storage, refreshedTokens);
66
+ await storeTokens(this.storage, refreshedTokens);
72
67
 
73
68
  return tokens;
74
69
  }
@@ -3,23 +3,23 @@ import { UserStorage } from "@/shared/lib/types.js";
3
3
  import { convertForwardedTokenFormat } from "@/lib/jwt.js";
4
4
 
5
5
  export interface UserSession {
6
- get(): User | null;
7
- set(user: User): void;
6
+ get(): Promise<User | null>;
7
+ set(user: User): Promise<void>;
8
8
  }
9
9
 
10
10
  export class GenericUserSession implements UserSession {
11
11
  constructor(readonly storage: AuthStorage) {}
12
12
 
13
- get(): User | null {
14
- const user = this.storage.get(UserStorage.USER);
13
+ async get(): Promise<User | null> {
14
+ const user = await this.storage.get(UserStorage.USER);
15
15
  return user ? JSON.parse(user) : null;
16
16
  }
17
17
 
18
- set(user: User | null): void {
18
+ async set(user: User | null): Promise<void> {
19
19
  const forwardedTokens = user?.forwardedTokens
20
20
  ? convertForwardedTokenFormat(user?.forwardedTokens as ForwardedTokensJWT)
21
21
  : null;
22
22
  const value = user ? JSON.stringify({ ...user, forwardedTokens }) : "";
23
- this.storage.set(UserStorage.USER, value);
23
+ await this.storage.set(UserStorage.USER, value);
24
24
  }
25
25
  }
@@ -3,7 +3,7 @@ import { parseJWT } from "oslo/jwt";
3
3
  import type { AuthStorage, User } from "@/types.js";
4
4
 
5
5
  export async function getUser(storage: AuthStorage): Promise<User | null> {
6
- const tokens = retrieveTokens(storage);
6
+ const tokens = await retrieveTokens(storage);
7
7
  if (!tokens) return null;
8
8
 
9
9
  // Assumes all information is in the ID token
@@ -35,6 +35,6 @@ export abstract class CookieStorage implements AuthStorage {
35
35
  path: settings.path ?? "/",
36
36
  };
37
37
  }
38
- abstract get(key: string): string | null;
39
- abstract set(key: string, value: string): void;
38
+ abstract get(key: string): Promise<string | null>;
39
+ abstract set(key: string, value: string): Promise<void>;
40
40
  }
@@ -83,7 +83,6 @@ export async function generateOauthLoginUrl(config: {
83
83
  // Required by the auth server for offline_access scope
84
84
  oAuthUrl.searchParams.append("prompt", "consent");
85
85
 
86
- console.log("Generated OAuth URL", oAuthUrl.toString());
87
86
  return oAuthUrl;
88
87
  }
89
88
 
@@ -139,36 +138,40 @@ export async function exchangeTokens(
139
138
  return tokens;
140
139
  }
141
140
 
142
- export function storeTokens(
141
+ export async function storeTokens(
143
142
  storage: AuthStorage,
144
143
  tokens: OIDCTokenResponseBody,
145
144
  ) {
146
145
  // store tokens in storage ( TODO we should probably store them against the state to allow multiple logins )
147
- storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);
148
- storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);
149
- if (tokens.refresh_token)
150
- storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);
146
+ await storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);
147
+ await storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);
148
+ if (tokens.refresh_token) {
149
+ await storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);
150
+ }
151
151
  }
152
152
 
153
- export function clearTokens(storage: AuthStorage) {
154
- Object.values(OAuthTokens).forEach((cookie) => {
155
- storage.set(cookie, "");
156
- });
157
- Object.values(CodeVerifier.COOKIE_NAME).forEach((cookie) => {
153
+ export async function clearTokens(storage: AuthStorage) {
154
+ const clearOAuthPromises = Object.values(OAuthTokens).map((cookie) => {
158
155
  storage.set(cookie, "");
159
156
  });
157
+ const clearCodeVerifierPromises = Object.values(CodeVerifier.COOKIE_NAME).map(
158
+ (cookie) => {
159
+ storage.set(cookie, "");
160
+ },
161
+ );
162
+ await Promise.all([...clearOAuthPromises, ...clearCodeVerifierPromises]);
160
163
  }
161
- export function clearUser(storage: AuthStorage) {
164
+ export async function clearUser(storage: AuthStorage) {
162
165
  const userSession = new GenericUserSession(storage);
163
- userSession.set(null);
166
+ await userSession.set(null);
164
167
  }
165
168
 
166
- export function retrieveTokens(
169
+ export async function retrieveTokens(
167
170
  storage: AuthStorage,
168
- ): OIDCTokenResponseBody | null {
169
- const idToken = storage.get(OAuthTokens.ID_TOKEN);
170
- const accessToken = storage.get(OAuthTokens.ACCESS_TOKEN);
171
- const refreshToken = storage.get(OAuthTokens.REFRESH_TOKEN);
171
+ ): Promise<OIDCTokenResponseBody | null> {
172
+ const idToken = await storage.get(OAuthTokens.ID_TOKEN);
173
+ const accessToken = await storage.get(OAuthTokens.ACCESS_TOKEN);
174
+ const refreshToken = await storage.get(OAuthTokens.REFRESH_TOKEN);
172
175
 
173
176
  if (!idToken || !accessToken) return null;
174
177
 
package/src/types.ts CHANGED
@@ -222,6 +222,6 @@ export type {
222
222
  };
223
223
 
224
224
  export interface AuthStorage {
225
- get(key: string): string | null;
226
- set(key: string, value: string): void;
225
+ get(key: string): Promise<string | null>;
226
+ set(key: string, value: string): Promise<void>;
227
227
  }
@@ -17,25 +17,25 @@ const mockUser: User = {
17
17
  describe("getUser", () => {
18
18
  beforeEach(() => {
19
19
  vi.clearAllMocks();
20
- vi.spyOn(GenericUserSession.prototype, "get").mockReturnValue(mockUser);
20
+ vi.spyOn(GenericUserSession.prototype, "get").mockResolvedValue(mockUser);
21
21
  vi.spyOn(NextjsClientStorage.prototype, "get").mockImplementation(
22
- (cookieName: string) => {
22
+ async (cookieName: string) => {
23
23
  switch (cookieName) {
24
24
  case "access_token":
25
- return "test-access-token";
25
+ return Promise.resolve("test-access-token");
26
26
  case "id_token":
27
- return "test-id-token";
27
+ return Promise.resolve("test-id-token");
28
28
  case "refresh_token":
29
- return "test-refresh-token";
29
+ return Promise.resolve("test-refresh-token");
30
30
  default:
31
- return null;
31
+ return Promise.resolve(null);
32
32
  }
33
33
  },
34
34
  );
35
35
  });
36
36
 
37
- it("should get the user from session", () => {
38
- const user = getUser();
37
+ it("should get the user from session", async () => {
38
+ const user = await getUser();
39
39
  expect(user).toEqual(mockUser);
40
40
  });
41
41
  });
@@ -12,7 +12,6 @@ exports[`Auth Client Public API Snapshot > should match the previous API snapsho
12
12
  "useIframe": [Function],
13
13
  "useSession": [Function],
14
14
  "useToken": [Function],
15
- "useTokenCookie": [Function],
16
15
  "useUser": [Function],
17
16
  }
18
17
  `;
@@ -1,20 +1,20 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
1
+ import { describe, it, expect, vi } from "vitest";
2
2
  import {
3
3
  resolveOAuthAccessCode,
4
4
  isLoggedIn,
5
5
  buildLoginUrl,
6
- } from "@/server/login.js";
7
- import { ServerAuthenticationResolver } from "@/server/ServerAuthenticationResolver.js";
8
- import { GenericAuthenticationInitiator } from "@/services/AuthenticationService.js";
6
+ } from "@/server/login";
7
+ import { ServerAuthenticationResolver } from "@/server/ServerAuthenticationResolver";
8
+ import { GenericAuthenticationInitiator } from "@/services/AuthenticationService";
9
9
  import { GenericPublicClientPKCEProducer } from "@/services/PKCE.js";
10
- import { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from "@/constants.js";
11
- import type { OIDCTokenResponseBody, AuthStorage } from "@/types.js";
12
- import type { AuthConfig } from "@/server/config.js";
13
- import type { PKCEProducer } from "@/services/types.js";
10
+ import { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from "@/constants";
11
+ import type { AuthStorage, OIDCTokenResponseBody } from "@/types.js";
12
+ import type { AuthConfig } from "@/server/config.ts";
13
+ import type { PKCEProducer } from "@/services/types.ts";
14
14
 
15
15
  vi.mock("@/server/ServerAuthenticationResolver");
16
16
  vi.mock("@/services/AuthenticationService");
17
- vi.mock("@/services/PKCE");
17
+ vi.mock("@/services/PKCE.js");
18
18
 
19
19
  class StubPKCEProducer implements PKCEProducer {
20
20
  constructor() {}
@@ -70,18 +70,18 @@ describe("Login Utilities", () => {
70
70
  });
71
71
 
72
72
  describe("isLoggedIn", () => {
73
- it("should return true if id_token is in storage", () => {
74
- vi.mocked(mockStorage.get).mockReturnValue("mockIdToken");
73
+ it("should return true if id_token is in storage", async () => {
74
+ vi.mocked(mockStorage.get).mockResolvedValue("mockIdToken");
75
75
 
76
- const result = isLoggedIn(mockStorage);
76
+ const result = await isLoggedIn(mockStorage);
77
77
 
78
78
  expect(result).toBe(true);
79
79
  });
80
80
 
81
- it("should return false if id_token is not in storage", () => {
82
- vi.mocked(mockStorage.get).mockReturnValue(null);
81
+ it("should return false if id_token is not in storage", async () => {
82
+ vi.mocked(mockStorage.get).mockResolvedValue(null);
83
83
 
84
- const result = isLoggedIn(mockStorage);
84
+ const result = await isLoggedIn(mockStorage);
85
85
 
86
86
  expect(result).toBe(false);
87
87
  });
@@ -171,9 +171,11 @@ describe("Login Utilities", () => {
171
171
  mockStorage,
172
172
  );
173
173
 
174
- expect(GenericAuthenticationInitiator).toHaveBeenCalledWith(expect.objectContaining({
175
- nonce,
176
- }));
174
+ expect(GenericAuthenticationInitiator).toHaveBeenCalledWith(
175
+ expect.objectContaining({
176
+ nonce,
177
+ }),
178
+ );
177
179
  });
178
180
  });
179
181
  });