@civic/auth 0.8.2-beta.1 → 0.8.3-beta.1
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/CHANGELOG.md +5 -0
- package/README.md +6 -0
- package/dist/lib/oauth.d.ts +4 -2
- package/dist/lib/oauth.d.ts.map +1 -1
- package/dist/lib/oauth.js +4 -2
- package/dist/lib/oauth.js.map +1 -1
- package/dist/nextjs/NextClientAuthenticationRefresher.d.ts +1 -1
- package/dist/nextjs/NextClientAuthenticationRefresher.d.ts.map +1 -1
- package/dist/nextjs/NextClientAuthenticationRefresher.js.map +1 -1
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts +1 -1
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.d.ts.map +1 -1
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.js +3 -0
- package/dist/nextjs/NextServerAuthenticationRefresherImpl.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +2 -1
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.d.ts +15 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.js +26 -1
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
- package/dist/reactjs/hooks/useUser.d.ts +3 -0
- package/dist/reactjs/hooks/useUser.d.ts.map +1 -1
- package/dist/reactjs/hooks/useUser.js +32 -0
- package/dist/reactjs/hooks/useUser.js.map +1 -1
- package/dist/reactjs/providers/CivicAuthContext.d.ts +4 -0
- package/dist/reactjs/providers/CivicAuthContext.d.ts.map +1 -1
- package/dist/reactjs/providers/CivicAuthContext.js +22 -13
- package/dist/reactjs/providers/CivicAuthContext.js.map +1 -1
- package/dist/reactjs/providers/CivicAuthProvider.d.ts +1 -0
- package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
- package/dist/reactjs/providers/CivicAuthProvider.js +3 -1
- package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
- package/dist/server/config.d.ts +47 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/index.d.ts +8 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/login.d.ts +9 -0
- package/dist/server/login.d.ts.map +1 -1
- package/dist/server/login.js +4 -2
- package/dist/server/login.js.map +1 -1
- package/dist/server/refresh.d.ts +1 -1
- package/dist/server/refresh.d.ts.map +1 -1
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/session.d.ts +60 -2
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js +216 -5
- package/dist/server/session.js.map +1 -1
- package/dist/server/types/express.d.ts +97 -0
- package/dist/server/types/express.d.ts.map +1 -0
- package/dist/server/types/express.js +2 -0
- package/dist/server/types/express.js.map +1 -0
- package/dist/services/AuthenticationService.d.ts +6 -0
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +48 -6
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/services/types.d.ts +1 -1
- package/dist/services/types.d.ts.map +1 -1
- package/dist/services/types.js.map +1 -1
- package/dist/shared/components/CivicAuthIframe.d.ts +1 -0
- package/dist/shared/components/CivicAuthIframe.d.ts.map +1 -1
- package/dist/shared/components/CivicAuthIframe.js +4 -4
- package/dist/shared/components/CivicAuthIframe.js.map +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.d.ts +2 -1
- package/dist/shared/components/CivicAuthIframeContainer.d.ts.map +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js +10 -3
- package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
- package/dist/shared/hooks/useSignIn.js +2 -1
- package/dist/shared/hooks/useSignIn.js.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.d.ts +2 -2
- package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
- package/dist/shared/lib/AuthenticationRefresherImpl.js +3 -0
- package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
- package/dist/shared/lib/GenericAuthenticationRefresher.d.ts +2 -2
- package/dist/shared/lib/GenericAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/GenericAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/iframeUtils.d.ts +1 -0
- package/dist/shared/lib/iframeUtils.d.ts.map +1 -1
- package/dist/shared/lib/iframeUtils.js +3 -0
- package/dist/shared/lib/iframeUtils.js.map +1 -1
- package/dist/shared/lib/util.d.ts +7 -0
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +12 -0
- package/dist/shared/lib/util.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts +41 -0
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts.map +1 -0
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js +125 -0
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js.map +1 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts +66 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +296 -10
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/SessionManager.d.ts +31 -3
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +253 -22
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +31 -18
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.js +14 -8
- package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts +34 -0
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +139 -0
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +1 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts +21 -0
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.js +52 -2
- package/dist/vanillajs/auth/handlers/MessageHandler.js.map +1 -1
- package/dist/vanillajs/auth/types/AuthTypes.d.ts +17 -0
- package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
- package/dist/vanillajs/auth/types/AuthTypes.js +1 -0
- package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.d.ts +36 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.js +205 -18
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
- package/dist/vanillajs/index.d.ts +2 -0
- package/dist/vanillajs/index.d.ts.map +1 -1
- package/dist/vanillajs/index.js +4 -0
- package/dist/vanillajs/index.js.map +1 -1
- package/dist/vanillajs/ui/LoadingComponents.d.ts.map +1 -1
- package/dist/vanillajs/ui/LoadingComponents.js +1 -1
- package/dist/vanillajs/ui/LoadingComponents.js.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AuthConfig } from "../../server/config.js";
|
|
2
|
+
import type { OIDCTokenResponseBody } from "../../types.js";
|
|
3
|
+
import { GenericAuthenticationRefresher } from "../../shared/lib/GenericAuthenticationRefresher.js";
|
|
4
|
+
import type { AuthenticationEvents } from "./AuthenticationEvents.js";
|
|
5
|
+
/**
|
|
6
|
+
* BackendAuthenticationRefresher handles token refresh for backend authentication flows
|
|
7
|
+
* by calling the backend's refresh API endpoint instead of accessing browser storage.
|
|
8
|
+
* This is used when loginUrl is configured, indicating backend integration.
|
|
9
|
+
*/
|
|
10
|
+
export declare class BackendAuthenticationRefresher extends GenericAuthenticationRefresher {
|
|
11
|
+
private logger;
|
|
12
|
+
private loginUrl;
|
|
13
|
+
private autoRefreshTimeoutId?;
|
|
14
|
+
private events?;
|
|
15
|
+
constructor(authConfig: AuthConfig, loginUrl: string, onError: (error: Error) => Promise<void>, events?: AuthenticationEvents);
|
|
16
|
+
static build(authConfig: AuthConfig, loginUrl: string, onError: (error: Error) => Promise<void>, events?: AuthenticationEvents): Promise<BackendAuthenticationRefresher>;
|
|
17
|
+
/**
|
|
18
|
+
* Override getRefreshToken to indicate that backend flows don't need browser-accessible refresh tokens
|
|
19
|
+
*/
|
|
20
|
+
getRefreshToken(): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Refresh tokens by calling the backend's refresh API endpoint
|
|
23
|
+
*/
|
|
24
|
+
refreshAccessToken(): Promise<OIDCTokenResponseBody | null>;
|
|
25
|
+
/**
|
|
26
|
+
* For backend flows, we don't need to store tokens in browser storage
|
|
27
|
+
* since they're managed server-side in HTTP-only cookies
|
|
28
|
+
*/
|
|
29
|
+
storeTokens(tokenResponseBody: OIDCTokenResponseBody | null): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Setup auto-refresh for backend flows
|
|
32
|
+
* Since we can't access token expiration from HTTP-only cookies,
|
|
33
|
+
* we'll use a conservative refresh interval
|
|
34
|
+
*/
|
|
35
|
+
setupAutorefresh(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Clear auto-refresh for backend flows
|
|
38
|
+
*/
|
|
39
|
+
clearAutorefresh(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=BackendAuthenticationRefresher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackendAuthenticationRefresher.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/auth/BackendAuthenticationRefresher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,8BAA8B,EAAE,MAAM,oDAAoD,CAAC;AAGpG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGtE;;;;GAIG;AACH,qBAAa,8BAA+B,SAAQ,8BAA8B;IAChF,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,MAAM,CAAC,CAAuB;gBAGpC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,MAAM,CAAC,EAAE,oBAAoB;WAWlB,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,8BAA8B,CAAC;IAS1C;;OAEG;IACY,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAOjD;;OAEG;IACY,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAuD1E;;;OAGG;IACG,WAAW,CACf,iBAAiB,EAAE,qBAAqB,GAAG,IAAI,GAC9C,OAAO,CAAC,IAAI,CAAC;IAQhB;;;;OAIG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BvC;;OAEG;IACH,gBAAgB,IAAI,IAAI;CAOzB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { GenericAuthenticationRefresher } from "../../shared/lib/GenericAuthenticationRefresher.js";
|
|
2
|
+
import { getBackendEndpoints } from "../../shared/lib/util.js";
|
|
3
|
+
import { createLogger } from "../utils/logger.js";
|
|
4
|
+
import { AuthEvent } from "../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* BackendAuthenticationRefresher handles token refresh for backend authentication flows
|
|
7
|
+
* by calling the backend's refresh API endpoint instead of accessing browser storage.
|
|
8
|
+
* This is used when loginUrl is configured, indicating backend integration.
|
|
9
|
+
*/
|
|
10
|
+
export class BackendAuthenticationRefresher extends GenericAuthenticationRefresher {
|
|
11
|
+
logger = createLogger("backend-auth-refresher");
|
|
12
|
+
loginUrl;
|
|
13
|
+
autoRefreshTimeoutId;
|
|
14
|
+
events;
|
|
15
|
+
constructor(authConfig, loginUrl, onError, events) {
|
|
16
|
+
super(onError);
|
|
17
|
+
this.authConfig = authConfig;
|
|
18
|
+
this.loginUrl = loginUrl;
|
|
19
|
+
this.events = events;
|
|
20
|
+
this.logger.info("BackendAuthenticationRefresher initialized", {
|
|
21
|
+
loginUrl: this.loginUrl,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
static async build(authConfig, loginUrl, onError, events) {
|
|
25
|
+
return new BackendAuthenticationRefresher(authConfig, loginUrl, onError, events);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Override getRefreshToken to indicate that backend flows don't need browser-accessible refresh tokens
|
|
29
|
+
*/
|
|
30
|
+
async getRefreshToken() {
|
|
31
|
+
// For backend flows, we don't need to retrieve the refresh token from browser storage
|
|
32
|
+
// The backend handles the refresh token internally via HTTP-only cookies
|
|
33
|
+
this.logger.debug("Backend flow: refresh token managed server-side");
|
|
34
|
+
return "backend-managed"; // Placeholder token
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Refresh tokens by calling the backend's refresh API endpoint
|
|
38
|
+
*/
|
|
39
|
+
async refreshAccessToken() {
|
|
40
|
+
try {
|
|
41
|
+
// Emit refresh started event
|
|
42
|
+
this.events?.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);
|
|
43
|
+
const backendUrl = new URL(this.loginUrl).origin;
|
|
44
|
+
const endpoints = getBackendEndpoints(this.authConfig?.backendEndpoints);
|
|
45
|
+
const refreshEndpoint = `${backendUrl}${endpoints.refresh}`;
|
|
46
|
+
this.logger.info("Calling backend refresh endpoint", {
|
|
47
|
+
endpoint: refreshEndpoint,
|
|
48
|
+
});
|
|
49
|
+
const response = await fetch(refreshEndpoint, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
credentials: "include", // Include HTTP-only cookies
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
58
|
+
const error = new Error(`Backend refresh failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
59
|
+
// Emit refresh error event
|
|
60
|
+
this.events?.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
this.logger.info("Backend token refresh successful");
|
|
64
|
+
// Emit refresh complete event
|
|
65
|
+
this.events?.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);
|
|
66
|
+
// For backend flows, tokens are managed in HTTP-only cookies
|
|
67
|
+
// and are not accessible to JavaScript, so we return null
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
this.logger.error("Backend token refresh failed", { error });
|
|
72
|
+
// Emit refresh error event if not already emitted
|
|
73
|
+
if (error instanceof Error &&
|
|
74
|
+
!error.message.includes("Backend refresh failed")) {
|
|
75
|
+
this.events?.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* For backend flows, we don't need to store tokens in browser storage
|
|
82
|
+
* since they're managed server-side in HTTP-only cookies
|
|
83
|
+
*/
|
|
84
|
+
async storeTokens(tokenResponseBody) {
|
|
85
|
+
this.logger.debug("Backend flow: tokens stored server-side, skipping browser storage", { tokenResponseBody });
|
|
86
|
+
// No-op for backend flows - tokens are stored server-side
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Setup auto-refresh for backend flows
|
|
90
|
+
* Since we can't access token expiration from HTTP-only cookies,
|
|
91
|
+
* we'll use a conservative refresh interval
|
|
92
|
+
*/
|
|
93
|
+
async setupAutorefresh() {
|
|
94
|
+
this.logger.info("Setting up auto-refresh for backend flow");
|
|
95
|
+
// Clear any existing timeout
|
|
96
|
+
this.clearAutorefresh();
|
|
97
|
+
// For backend flows, we can't read token expiration from HTTP-only cookies
|
|
98
|
+
// So we'll use a conservative refresh interval (e.g., every 50 minutes for 1-hour tokens)
|
|
99
|
+
const refreshIntervalMs = 50 * 60 * 1000; // 50 minutes
|
|
100
|
+
this.autoRefreshTimeoutId = window.setTimeout(async () => {
|
|
101
|
+
try {
|
|
102
|
+
this.logger.info("Auto-refreshing backend tokens");
|
|
103
|
+
await this.refreshTokens();
|
|
104
|
+
// Schedule next refresh
|
|
105
|
+
this.setupAutorefresh();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
this.logger.error("Auto-refresh failed", { error });
|
|
109
|
+
await this.onError(error);
|
|
110
|
+
}
|
|
111
|
+
}, refreshIntervalMs);
|
|
112
|
+
this.logger.info(`Next backend token refresh scheduled in ${refreshIntervalMs / (60 * 1000)} minutes`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Clear auto-refresh for backend flows
|
|
116
|
+
*/
|
|
117
|
+
clearAutorefresh() {
|
|
118
|
+
if (this.autoRefreshTimeoutId) {
|
|
119
|
+
this.logger.debug("Clearing auto-refresh timeout for backend flow");
|
|
120
|
+
window.clearTimeout(this.autoRefreshTimeoutId);
|
|
121
|
+
this.autoRefreshTimeoutId = undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=BackendAuthenticationRefresher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackendAuthenticationRefresher.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/BackendAuthenticationRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthConfig } from \"../../server/config.js\";\nimport type { OIDCTokenResponseBody } from \"../../types.js\";\nimport { GenericAuthenticationRefresher } from \"../../shared/lib/GenericAuthenticationRefresher.js\";\nimport { getBackendEndpoints } from \"../../shared/lib/util.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport { AuthEvent } from \"../types/index.js\";\n\n/**\n * BackendAuthenticationRefresher handles token refresh for backend authentication flows\n * by calling the backend's refresh API endpoint instead of accessing browser storage.\n * This is used when loginUrl is configured, indicating backend integration.\n */\nexport class BackendAuthenticationRefresher extends GenericAuthenticationRefresher {\n private logger = createLogger(\"backend-auth-refresher\");\n private loginUrl: string;\n private autoRefreshTimeoutId?: number;\n private events?: AuthenticationEvents;\n\n constructor(\n authConfig: AuthConfig,\n loginUrl: string,\n onError: (error: Error) => Promise<void>,\n events?: AuthenticationEvents,\n ) {\n super(onError);\n this.authConfig = authConfig;\n this.loginUrl = loginUrl;\n this.events = events;\n this.logger.info(\"BackendAuthenticationRefresher initialized\", {\n loginUrl: this.loginUrl,\n });\n }\n\n static async build(\n authConfig: AuthConfig,\n loginUrl: string,\n onError: (error: Error) => Promise<void>,\n events?: AuthenticationEvents,\n ): Promise<BackendAuthenticationRefresher> {\n return new BackendAuthenticationRefresher(\n authConfig,\n loginUrl,\n onError,\n events,\n );\n }\n\n /**\n * Override getRefreshToken to indicate that backend flows don't need browser-accessible refresh tokens\n */\n override async getRefreshToken(): Promise<string> {\n // For backend flows, we don't need to retrieve the refresh token from browser storage\n // The backend handles the refresh token internally via HTTP-only cookies\n this.logger.debug(\"Backend flow: refresh token managed server-side\");\n return \"backend-managed\"; // Placeholder token\n }\n\n /**\n * Refresh tokens by calling the backend's refresh API endpoint\n */\n override async refreshAccessToken(): Promise<OIDCTokenResponseBody | null> {\n try {\n // Emit refresh started event\n this.events?.emit(AuthEvent.TOKEN_REFRESH_STARTED, null);\n\n const backendUrl = new URL(this.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.authConfig?.backendEndpoints);\n const refreshEndpoint = `${backendUrl}${endpoints.refresh}`;\n\n this.logger.info(\"Calling backend refresh endpoint\", {\n endpoint: refreshEndpoint,\n });\n\n const response = await fetch(refreshEndpoint, {\n method: \"POST\",\n credentials: \"include\", // Include HTTP-only cookies\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n const error = new Error(\n `Backend refresh failed: ${response.status} ${response.statusText} - ${errorText}`,\n );\n\n // Emit refresh error event\n this.events?.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n throw error;\n }\n\n this.logger.info(\"Backend token refresh successful\");\n\n // Emit refresh complete event\n this.events?.emit(AuthEvent.TOKEN_REFRESH_COMPLETE, null);\n\n // For backend flows, tokens are managed in HTTP-only cookies\n // and are not accessible to JavaScript, so we return null\n return null;\n } catch (error) {\n this.logger.error(\"Backend token refresh failed\", { error });\n\n // Emit refresh error event if not already emitted\n if (\n error instanceof Error &&\n !error.message.includes(\"Backend refresh failed\")\n ) {\n this.events?.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n\n throw error;\n }\n }\n\n /**\n * For backend flows, we don't need to store tokens in browser storage\n * since they're managed server-side in HTTP-only cookies\n */\n async storeTokens(\n tokenResponseBody: OIDCTokenResponseBody | null,\n ): Promise<void> {\n this.logger.debug(\n \"Backend flow: tokens stored server-side, skipping browser storage\",\n { tokenResponseBody },\n );\n // No-op for backend flows - tokens are stored server-side\n }\n\n /**\n * Setup auto-refresh for backend flows\n * Since we can't access token expiration from HTTP-only cookies,\n * we'll use a conservative refresh interval\n */\n async setupAutorefresh(): Promise<void> {\n this.logger.info(\"Setting up auto-refresh for backend flow\");\n\n // Clear any existing timeout\n this.clearAutorefresh();\n\n // For backend flows, we can't read token expiration from HTTP-only cookies\n // So we'll use a conservative refresh interval (e.g., every 50 minutes for 1-hour tokens)\n const refreshIntervalMs = 50 * 60 * 1000; // 50 minutes\n\n this.autoRefreshTimeoutId = window.setTimeout(async () => {\n try {\n this.logger.info(\"Auto-refreshing backend tokens\");\n await this.refreshTokens();\n // Schedule next refresh\n this.setupAutorefresh();\n } catch (error) {\n this.logger.error(\"Auto-refresh failed\", { error });\n await this.onError(error as Error);\n }\n }, refreshIntervalMs);\n\n this.logger.info(\n `Next backend token refresh scheduled in ${refreshIntervalMs / (60 * 1000)} minutes`,\n );\n }\n\n /**\n * Clear auto-refresh for backend flows\n */\n clearAutorefresh(): void {\n if (this.autoRefreshTimeoutId) {\n this.logger.debug(\"Clearing auto-refresh timeout for backend flow\");\n window.clearTimeout(this.autoRefreshTimeoutId);\n this.autoRefreshTimeoutId = undefined;\n }\n }\n}\n"]}
|
|
@@ -19,6 +19,7 @@ export declare class CivicAuth {
|
|
|
19
19
|
private authProcessTimeoutHandle?;
|
|
20
20
|
private popupFailureTimeoutHandle?;
|
|
21
21
|
private hasPopupFailed;
|
|
22
|
+
private loginUrl?;
|
|
22
23
|
private messageHandler?;
|
|
23
24
|
private popupHandler?;
|
|
24
25
|
private iframeAuthHandler?;
|
|
@@ -37,6 +38,7 @@ export declare class CivicAuth {
|
|
|
37
38
|
*
|
|
38
39
|
* @example
|
|
39
40
|
* ```typescript
|
|
41
|
+
* // Standard SPA authentication
|
|
40
42
|
* const auth = await CivicAuth.create({
|
|
41
43
|
* clientId: "your-client-id",
|
|
42
44
|
* // redirectUrl is optional - defaults to current page (window.location.origin + window.location.pathname)
|
|
@@ -52,6 +54,12 @@ export declare class CivicAuth {
|
|
|
52
54
|
* success: "Authentication successful!"
|
|
53
55
|
* }
|
|
54
56
|
* });
|
|
57
|
+
*
|
|
58
|
+
* // Backend integration authentication
|
|
59
|
+
* const authWithBackend = await CivicAuth.create({
|
|
60
|
+
* clientId: "your-client-id",
|
|
61
|
+
* loginUrl: "http://example.com/custom-backendurl" // Automatically uses BrowserCookieStorage
|
|
62
|
+
* });
|
|
55
63
|
* ```
|
|
56
64
|
*/
|
|
57
65
|
static create(config: CivicAuthClientConfig): Promise<CivicAuth>;
|
|
@@ -63,16 +71,44 @@ export declare class CivicAuth {
|
|
|
63
71
|
* Initialize all handlers with proper configuration
|
|
64
72
|
*/
|
|
65
73
|
private initializeHandlers;
|
|
74
|
+
/**
|
|
75
|
+
* Set up automatic re-preloading when authentication is cancelled by user
|
|
76
|
+
* This maintains instant sign-in experience for subsequent attempts
|
|
77
|
+
*/
|
|
78
|
+
private setupAutoRepreload;
|
|
66
79
|
/**
|
|
67
80
|
* Builds the authentication URL with PKCE challenge
|
|
68
81
|
*/
|
|
69
82
|
private buildAuthUrl;
|
|
83
|
+
/**
|
|
84
|
+
* Preloads the authentication iframe for instant sign-in
|
|
85
|
+
* This creates the iframe in the background but keeps it hidden until startAuthentication() is called
|
|
86
|
+
* @throws {CivicAuthError} If preloading fails or is not supported
|
|
87
|
+
* @private - This method is used internally for automatic preloading
|
|
88
|
+
*/
|
|
89
|
+
private preloadAuthentication;
|
|
90
|
+
/**
|
|
91
|
+
* Check if authentication is preloaded and ready for instant sign-in
|
|
92
|
+
* @returns True if an iframe is preloaded and ready
|
|
93
|
+
*/
|
|
94
|
+
isAuthenticationPreloaded(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Enable or disable iframe preloading
|
|
97
|
+
* @param enabled Whether to enable iframe preloading
|
|
98
|
+
*/
|
|
99
|
+
setPreloadEnabled(enabled: boolean): void;
|
|
100
|
+
/**
|
|
101
|
+
* Check if iframe preloading is enabled
|
|
102
|
+
* @returns True if iframe preloading is enabled
|
|
103
|
+
*/
|
|
104
|
+
getPreloadEnabled(): boolean;
|
|
70
105
|
/**
|
|
71
106
|
* Starts the authentication process
|
|
72
107
|
* @returns A promise that resolves with the authentication result
|
|
73
108
|
* @throws {CivicAuthError} If authentication fails or times out
|
|
74
109
|
*/
|
|
75
110
|
startAuthentication(): Promise<AuthResult>;
|
|
111
|
+
private handleBrowserCorsFailsSilently;
|
|
76
112
|
/**
|
|
77
113
|
* Handle authentication based on display mode
|
|
78
114
|
*/
|
|
@@ -150,6 +186,36 @@ export declare class CivicAuth {
|
|
|
150
186
|
isAuthenticated: boolean;
|
|
151
187
|
isAutoRefreshActive: boolean;
|
|
152
188
|
} | null;
|
|
189
|
+
/**
|
|
190
|
+
* Set a custom login URL for backend integration.
|
|
191
|
+
* This is useful when integrating with a backend that handles the OAuth flow.
|
|
192
|
+
* Alternatively, you can configure this directly in CivicAuth.create().
|
|
193
|
+
*
|
|
194
|
+
* @param loginUrl - The custom login URL to use (e.g., "http://localhost:3020/auth/login")
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* // Option 1: Configure in create()
|
|
199
|
+
* const authClient = await CivicAuth.create({
|
|
200
|
+
* clientId: "YOUR_CLIENT_ID",
|
|
201
|
+
* loginUrl: "http://example.com/custom-backendurl"
|
|
202
|
+
* });
|
|
203
|
+
*
|
|
204
|
+
* // Option 2: Set after creation
|
|
205
|
+
* civicAuth.setLoginUrl("http://localhost:3020/auth/login");
|
|
206
|
+
* await civicAuth.startAuthentication();
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
setLoginUrl(loginUrl: string): void;
|
|
210
|
+
/**
|
|
211
|
+
* Clear the login URL and return to standard OAuth flow
|
|
212
|
+
*/
|
|
213
|
+
clearLoginUrl(): void;
|
|
214
|
+
/**
|
|
215
|
+
* Get the current login URL
|
|
216
|
+
* @returns The current login URL or undefined if not set
|
|
217
|
+
*/
|
|
218
|
+
getLoginUrl(): string | undefined;
|
|
153
219
|
/**
|
|
154
220
|
* Update the iframe display mode
|
|
155
221
|
* @param mode - The display mode to use for the iframe
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CivicAuth.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/auth/CivicAuth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"CivicAuth.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/auth/CivicAuth.ts"],"names":[],"mappings":"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"}
|