@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.
- package/.turbo/turbo-build.log +3 -3
- package/.turbo/turbo-lint.log +2 -9
- package/.turbo/turbo-test.log +396 -474
- package/CHANGELOG.md +2 -0
- package/dist/cjs/src/browser/storage.d.ts +2 -2
- package/dist/cjs/src/browser/storage.d.ts.map +1 -1
- package/dist/cjs/src/browser/storage.js +3 -3
- package/dist/cjs/src/browser/storage.js.map +1 -1
- package/dist/cjs/src/nextjs/GetUser.d.ts +1 -1
- package/dist/cjs/src/nextjs/GetUser.d.ts.map +1 -1
- package/dist/cjs/src/nextjs/GetUser.js +3 -3
- package/dist/cjs/src/nextjs/GetUser.js.map +1 -1
- package/dist/cjs/src/nextjs/config.d.ts.map +1 -1
- package/dist/cjs/src/nextjs/config.js +0 -2
- package/dist/cjs/src/nextjs/config.js.map +1 -1
- package/dist/cjs/src/nextjs/cookies.d.ts +4 -4
- package/dist/cjs/src/nextjs/cookies.d.ts.map +1 -1
- package/dist/cjs/src/nextjs/cookies.js +14 -11
- package/dist/cjs/src/nextjs/cookies.js.map +1 -1
- package/dist/cjs/src/nextjs/index.d.ts +1 -1
- package/dist/cjs/src/nextjs/index.d.ts.map +1 -1
- package/dist/cjs/src/nextjs/index.js.map +1 -1
- package/dist/cjs/src/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/cjs/src/nextjs/routeHandler.js +1 -5
- package/dist/cjs/src/nextjs/routeHandler.js.map +1 -1
- package/dist/cjs/src/reactjs/hooks/index.d.ts +0 -1
- package/dist/cjs/src/reactjs/hooks/index.d.ts.map +1 -1
- package/dist/cjs/src/reactjs/hooks/index.js +1 -3
- package/dist/cjs/src/reactjs/hooks/index.js.map +1 -1
- package/dist/cjs/src/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/cjs/src/server/ServerAuthenticationResolver.js +2 -7
- package/dist/cjs/src/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/cjs/src/server/login.d.ts +2 -2
- package/dist/cjs/src/server/login.d.ts.map +1 -1
- package/dist/cjs/src/server/login.js +2 -2
- package/dist/cjs/src/server/login.js.map +1 -1
- package/dist/cjs/src/services/AuthenticationService.d.ts.map +1 -1
- package/dist/cjs/src/services/AuthenticationService.js +6 -16
- package/dist/cjs/src/services/AuthenticationService.js.map +1 -1
- package/dist/cjs/src/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
- package/dist/cjs/src/shared/components/CivicAuthIframeContainer.js +0 -2
- package/dist/cjs/src/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/cjs/src/shared/components/LoadingIcon.d.ts.map +1 -1
- package/dist/cjs/src/shared/components/LoadingIcon.js +6 -0
- package/dist/cjs/src/shared/components/LoadingIcon.js.map +1 -1
- package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
- package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.js +2 -6
- package/dist/cjs/src/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
- package/dist/cjs/src/shared/lib/UserSession.d.ts +4 -4
- package/dist/cjs/src/shared/lib/UserSession.d.ts.map +1 -1
- package/dist/cjs/src/shared/lib/UserSession.js +4 -4
- package/dist/cjs/src/shared/lib/UserSession.js.map +1 -1
- package/dist/cjs/src/shared/lib/session.js +1 -1
- package/dist/cjs/src/shared/lib/session.js.map +1 -1
- package/dist/cjs/src/shared/lib/storage.d.ts +2 -2
- package/dist/cjs/src/shared/lib/storage.d.ts.map +1 -1
- package/dist/cjs/src/shared/lib/storage.js.map +1 -1
- package/dist/cjs/src/shared/lib/util.d.ts +4 -4
- package/dist/cjs/src/shared/lib/util.d.ts.map +1 -1
- package/dist/cjs/src/shared/lib/util.js +16 -15
- package/dist/cjs/src/shared/lib/util.js.map +1 -1
- package/dist/cjs/src/types.d.ts +2 -2
- package/dist/cjs/src/types.d.ts.map +1 -1
- package/dist/cjs/src/types.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/browser/storage.d.ts +2 -2
- package/dist/esm/src/browser/storage.d.ts.map +1 -1
- package/dist/esm/src/browser/storage.js +3 -3
- package/dist/esm/src/browser/storage.js.map +1 -1
- package/dist/esm/src/nextjs/GetUser.d.ts +1 -1
- package/dist/esm/src/nextjs/GetUser.d.ts.map +1 -1
- package/dist/esm/src/nextjs/GetUser.js +3 -3
- package/dist/esm/src/nextjs/GetUser.js.map +1 -1
- package/dist/esm/src/nextjs/config.d.ts.map +1 -1
- package/dist/esm/src/nextjs/config.js +0 -2
- package/dist/esm/src/nextjs/config.js.map +1 -1
- package/dist/esm/src/nextjs/cookies.d.ts +4 -4
- package/dist/esm/src/nextjs/cookies.d.ts.map +1 -1
- package/dist/esm/src/nextjs/cookies.js +14 -11
- package/dist/esm/src/nextjs/cookies.js.map +1 -1
- package/dist/esm/src/nextjs/index.d.ts +1 -1
- package/dist/esm/src/nextjs/index.d.ts.map +1 -1
- package/dist/esm/src/nextjs/index.js +1 -1
- package/dist/esm/src/nextjs/index.js.map +1 -1
- package/dist/esm/src/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/esm/src/nextjs/routeHandler.js +1 -5
- package/dist/esm/src/nextjs/routeHandler.js.map +1 -1
- package/dist/esm/src/reactjs/hooks/index.d.ts +0 -1
- package/dist/esm/src/reactjs/hooks/index.d.ts.map +1 -1
- package/dist/esm/src/reactjs/hooks/index.js +0 -1
- package/dist/esm/src/reactjs/hooks/index.js.map +1 -1
- package/dist/esm/src/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/esm/src/server/ServerAuthenticationResolver.js +2 -7
- package/dist/esm/src/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/esm/src/server/login.d.ts +2 -2
- package/dist/esm/src/server/login.d.ts.map +1 -1
- package/dist/esm/src/server/login.js +2 -2
- package/dist/esm/src/server/login.js.map +1 -1
- package/dist/esm/src/services/AuthenticationService.d.ts.map +1 -1
- package/dist/esm/src/services/AuthenticationService.js +6 -16
- package/dist/esm/src/services/AuthenticationService.js.map +1 -1
- package/dist/esm/src/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
- package/dist/esm/src/shared/components/CivicAuthIframeContainer.js +0 -2
- package/dist/esm/src/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/esm/src/shared/components/LoadingIcon.d.ts.map +1 -1
- package/dist/esm/src/shared/components/LoadingIcon.js +6 -0
- package/dist/esm/src/shared/components/LoadingIcon.js.map +1 -1
- package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
- package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.js +2 -6
- package/dist/esm/src/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
- package/dist/esm/src/shared/lib/UserSession.d.ts +4 -4
- package/dist/esm/src/shared/lib/UserSession.d.ts.map +1 -1
- package/dist/esm/src/shared/lib/UserSession.js +4 -4
- package/dist/esm/src/shared/lib/UserSession.js.map +1 -1
- package/dist/esm/src/shared/lib/session.js +1 -1
- package/dist/esm/src/shared/lib/session.js.map +1 -1
- package/dist/esm/src/shared/lib/storage.d.ts +2 -2
- package/dist/esm/src/shared/lib/storage.d.ts.map +1 -1
- package/dist/esm/src/shared/lib/storage.js.map +1 -1
- package/dist/esm/src/shared/lib/util.d.ts +4 -4
- package/dist/esm/src/shared/lib/util.d.ts.map +1 -1
- package/dist/esm/src/shared/lib/util.js +16 -15
- package/dist/esm/src/shared/lib/util.js.map +1 -1
- package/dist/esm/src/types.d.ts +2 -2
- package/dist/esm/src/types.d.ts.map +1 -1
- package/dist/esm/src/types.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/browser/storage.ts +3 -3
- package/src/nextjs/GetUser.ts +3 -3
- package/src/nextjs/config.ts +0 -2
- package/src/nextjs/cookies.ts +14 -18
- package/src/nextjs/index.ts +1 -3
- package/src/nextjs/routeHandler.ts +1 -5
- package/src/reactjs/hooks/index.ts +0 -1
- package/src/server/ServerAuthenticationResolver.ts +2 -7
- package/src/server/login.ts +8 -7
- package/src/services/AuthenticationService.ts +6 -16
- package/src/shared/components/CivicAuthIframeContainer.tsx +0 -4
- package/src/shared/components/LoadingIcon.tsx +8 -0
- package/src/shared/lib/GenericAuthenticationRefresher.ts +3 -8
- package/src/shared/lib/UserSession.ts +6 -6
- package/src/shared/lib/session.ts +1 -1
- package/src/shared/lib/storage.ts +2 -2
- package/src/shared/lib/util.ts +21 -18
- package/src/types.ts +2 -2
- package/test/unit/nextjs/getUser.test.ts +8 -8
- package/test/unit/publicApi/__snapshots__/apiSnapshot.test.ts.snap +0 -1
- package/test/unit/server/login.test.ts +20 -18
- package/test/unit/server/session.test.ts +4 -4
- package/test/unit/services/AuthenticationService.test.ts +3 -3
- package/test/unit/services/ServerAuthenticationResolver.test.ts +11 -6
- package/test/unit/shared/GenericAuthenticationRefresher.test.ts +4 -4
- package/test/unit/shared/UserSession.test.ts +6 -6
- 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.
|
|
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"
|
package/src/browser/storage.ts
CHANGED
|
@@ -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
|
}
|
package/src/nextjs/GetUser.ts
CHANGED
|
@@ -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 {
|
package/src/nextjs/config.ts
CHANGED
|
@@ -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
|
*/
|
package/src/nextjs/cookies.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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()
|
|
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
|
|
package/src/nextjs/index.ts
CHANGED
|
@@ -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
|
|
package/src/server/login.ts
CHANGED
|
@@ -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, "
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
}
|
|
@@ -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
|
}
|
package/src/shared/lib/util.ts
CHANGED
|
@@ -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).
|
|
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
|
@@ -17,25 +17,25 @@ const mockUser: User = {
|
|
|
17
17
|
describe("getUser", () => {
|
|
18
18
|
beforeEach(() => {
|
|
19
19
|
vi.clearAllMocks();
|
|
20
|
-
vi.spyOn(GenericUserSession.prototype, "get").
|
|
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
|
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { describe, it, expect, vi
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
resolveOAuthAccessCode,
|
|
4
4
|
isLoggedIn,
|
|
5
5
|
buildLoginUrl,
|
|
6
|
-
} from "@/server/login
|
|
7
|
-
import { ServerAuthenticationResolver } from "@/server/ServerAuthenticationResolver
|
|
8
|
-
import { GenericAuthenticationInitiator } from "@/services/AuthenticationService
|
|
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
|
|
11
|
-
import type {
|
|
12
|
-
import type { AuthConfig } from "@/server/config.
|
|
13
|
-
import type { PKCEProducer } from "@/services/types.
|
|
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).
|
|
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).
|
|
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(
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
expect(GenericAuthenticationInitiator).toHaveBeenCalledWith(
|
|
175
|
+
expect.objectContaining({
|
|
176
|
+
nonce,
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
177
179
|
});
|
|
178
180
|
});
|
|
179
181
|
});
|