@logto/client 1.0.0-beta.0 → 1.0.0-beta.4
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/README.md +53 -0
- package/lib/index.d.ts +16 -17
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +78 -73
- package/lib/index.js.map +1 -1
- package/lib/module.js +79 -74
- package/lib/module.js.map +1 -1
- package/package.json +13 -13
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Logto Client SDK
|
|
2
|
+
[](https://www.npmjs.com/package/@logto/client)
|
|
3
|
+
[](https://github.com/logto-io/js/actions/workflows/main.yml)
|
|
4
|
+
[](https://app.codecov.io/gh/logto-io/js?branch=master)
|
|
5
|
+
|
|
6
|
+
The Logto JavaScript Client SDK written in TypeScript. Check out our [docs](https://docs.logto.io/sdk/JavaScript/client/) for more information.
|
|
7
|
+
|
|
8
|
+
We also provide [文档](https://docs.logto.io/zh-cn/sdk/JavaScript/sdk/client/) in Simplified Chinese.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
### Using npm
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @logto/client
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Using yarn
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
yarn add @logto/client
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Using pnpm
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @logto/client
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## What is this and how does it work?
|
|
31
|
+
|
|
32
|
+
Logto JavaScript Client SDK is platformless, and is the foundation of the other platform's SDKs (Browser, Next.js, React, Vue, etc.). Usually you are not expected to use it directly in your application, as we have released a set of official SDKs to help you integrate Logto with your favorite JavaScript frameworks. [Check this out](https://docs.logto.io/docs/recipes/integrate-logto/) and get started!
|
|
33
|
+
|
|
34
|
+
If Logto does not support your framework and you want to contribute by building a new SDK, we recommend checking out our [Browser SDK](https://github.com/logto-io/js/tree/master/packages/browser) and [Node.js SDK](https://github.com/logto-io/js/tree/master/packages/node) and start from there.
|
|
35
|
+
|
|
36
|
+
### Adapters
|
|
37
|
+
|
|
38
|
+
To implement a platform-specific SDK, you should implement the following adapters:
|
|
39
|
+
|
|
40
|
+
1. requester: send http requests.
|
|
41
|
+
2. storage: save tokens and other info.
|
|
42
|
+
3. navigate: handle redirect.
|
|
43
|
+
4. generateState: generate state.
|
|
44
|
+
5. generateCodeVerifier: generate code verifier.
|
|
45
|
+
6. generateCodeChallenge: generate code challenge.
|
|
46
|
+
|
|
47
|
+
See the [adapters.ts](./src/adapter.ts) for more information.
|
|
48
|
+
|
|
49
|
+
## Resources
|
|
50
|
+
|
|
51
|
+
[](https://logto.io/)
|
|
52
|
+
[](https://docs.logto.io/sdk/JavaScript/js/)
|
|
53
|
+
[](https://discord.gg/UEPaF3j5e6)
|
package/lib/index.d.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { Requester, Prompt, IdTokenClaims } from "@logto/js";
|
|
|
2
2
|
import { Nullable, NormalizeKeyPaths } from "@silverhand/essentials";
|
|
3
3
|
import { Infer } from "superstruct";
|
|
4
4
|
export type StorageKey = 'idToken' | 'refreshToken' | 'accessToken' | 'signInSession';
|
|
5
|
-
export
|
|
6
|
-
getItem(key: StorageKey): Nullable<string
|
|
7
|
-
setItem(key: StorageKey, value: string): void
|
|
8
|
-
removeItem(key: StorageKey): void
|
|
9
|
-
}
|
|
5
|
+
export type Storage = {
|
|
6
|
+
getItem(key: StorageKey): Promise<Nullable<string>>;
|
|
7
|
+
setItem(key: StorageKey, value: string): Promise<void>;
|
|
8
|
+
removeItem(key: StorageKey): Promise<void>;
|
|
9
|
+
};
|
|
10
10
|
type Navigate = (url: string) => void;
|
|
11
11
|
export type ClientAdapter = {
|
|
12
12
|
requester: Requester;
|
|
@@ -21,9 +21,9 @@ declare const logtoClientErrorCodes: Readonly<{
|
|
|
21
21
|
invalid: string;
|
|
22
22
|
not_found: string;
|
|
23
23
|
};
|
|
24
|
-
not_authenticated:
|
|
25
|
-
get_access_token_by_refresh_token_failed:
|
|
26
|
-
invalid_id_token:
|
|
24
|
+
not_authenticated: "Not authenticated.";
|
|
25
|
+
get_access_token_by_refresh_token_failed: "Failed to get access token by refresh token.";
|
|
26
|
+
invalid_id_token: "Invalid id token.";
|
|
27
27
|
}>;
|
|
28
28
|
export type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;
|
|
29
29
|
export class LogtoClientError extends Error {
|
|
@@ -34,6 +34,7 @@ export class LogtoClientError extends Error {
|
|
|
34
34
|
export type LogtoConfig = {
|
|
35
35
|
endpoint: string;
|
|
36
36
|
appId: string;
|
|
37
|
+
appSecret?: string;
|
|
37
38
|
scopes?: string[];
|
|
38
39
|
resources?: string[];
|
|
39
40
|
prompt?: Prompt;
|
|
@@ -78,19 +79,17 @@ export default class LogtoClient {
|
|
|
78
79
|
expiresAt: number;
|
|
79
80
|
}>;
|
|
80
81
|
constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
get refreshToken(): Nullable<string>;
|
|
85
|
-
private set refreshToken(value);
|
|
86
|
-
get idToken(): Nullable<string>;
|
|
87
|
-
private set idToken(value);
|
|
82
|
+
isAuthenticated(): Promise<boolean>;
|
|
83
|
+
getRefreshToken(): Promise<Nullable<string>>;
|
|
84
|
+
getIdToken(): Promise<Nullable<string>>;
|
|
88
85
|
getAccessToken(resource?: string): Promise<string>;
|
|
89
|
-
getIdTokenClaims(): IdTokenClaims
|
|
86
|
+
getIdTokenClaims(): Promise<IdTokenClaims>;
|
|
90
87
|
signIn(redirectUri: string): Promise<void>;
|
|
91
|
-
isSignInRedirected(url: string): boolean
|
|
88
|
+
isSignInRedirected(url: string): Promise<boolean>;
|
|
92
89
|
handleSignInCallback(callbackUri: string): Promise<void>;
|
|
93
90
|
signOut(postLogoutRedirectUri?: string): Promise<void>;
|
|
91
|
+
protected getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>>;
|
|
92
|
+
protected setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>): Promise<void>;
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/client/src/src/adapter.ts","packages/client/src/src/errors.ts","packages/client/src/src/types/index.ts","packages/client/src/src/utils/requester.ts","packages/client/src/src/utils/index.ts","packages/client/src/src/index.ts","packages/client/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,"import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n\n protected readonly adapter: ClientAdapter;\n\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n private _idToken: Nullable<string>;\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n this._idToken = this.adapter.storage.getItem('idToken');\n\n if (this.logtoConfig.persistAccessToken) {\n this.loadAccessTokenMap();\n }\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected set signInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n get refreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n get idToken() {\n return this._idToken;\n }\n\n private set idToken(idToken: Nullable<string>) {\n this._idToken = idToken;\n\n if (!idToken) {\n this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n this.adapter.storage.setItem('idToken', idToken);\n }\n\n // eslint-disable-next-line complexity\n public async getAccessToken(resource?: string): Promise<string> {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n public getIdTokenClaims(): IdTokenClaims {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(this.idToken);\n }\n\n public async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n this.signInSession = { redirectUri, codeVerifier, state };\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(signInUri);\n }\n\n public isSignInRedirected(url: string): boolean {\n const { signInSession } = this;\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n public async handleSignInCallback(callbackUri: string) {\n const { signInSession, logtoConfig, adapter } = this;\n const { requester } = adapter;\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n\n this.saveCodeToken(codeTokenResponse);\n this.signInSession = null;\n }\n\n public async signOut(postLogoutRedirectUri?: string) {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n\n if (this.refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, this.refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken: this.idToken,\n });\n\n this.accessTokenMap.clear();\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(url);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n if (!this.refreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: this.refreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n this.saveAccessTokenMap();\n\n this.refreshToken = refreshToken;\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n this.idToken = idToken;\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n this.refreshToken = refreshToken ?? null;\n this.idToken = idToken;\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n this.saveAccessTokenMap();\n }\n\n private saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private loadAccessTokenMap() {\n const raw = this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/client/src/src/adapter.ts","packages/client/src/src/errors.ts","packages/client/src/src/types/index.ts","packages/client/src/src/utils/requester.ts","packages/client/src/src/utils/index.ts","packages/client/src/src/index.ts","packages/client/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,"import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n if (this.logtoConfig.persistAccessToken) {\n void this.loadAccessTokenMap();\n }\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
package/lib/index.js
CHANGED
|
@@ -95,8 +95,10 @@ const $b455f57f80fbf6bf$export$8d54726fdbf08e0a = (fetchFunction)=>{
|
|
|
95
95
|
return async (...args)=>{
|
|
96
96
|
const response = await fetchFunction(...args);
|
|
97
97
|
if (!response.ok) {
|
|
98
|
+
const responseJson = await response.json();
|
|
99
|
+
if (!(0, $4R6L3$logtojs.logtoRequestErrorSchema).is(responseJson)) throw new (0, $4R6L3$logtojs.LogtoError)("unexpected_response_error", responseJson);
|
|
98
100
|
// Expected request error from server
|
|
99
|
-
const { code: code , message: message } =
|
|
101
|
+
const { code: code , message: message } = responseJson;
|
|
100
102
|
throw new (0, $4R6L3$logtojs.LogtoRequestError)(code, message);
|
|
101
103
|
}
|
|
102
104
|
return response.json();
|
|
@@ -124,55 +126,20 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
124
126
|
scopes: (0, $4R6L3$logtojs.withReservedScopes)(logtoConfig.scopes).split(" ")
|
|
125
127
|
};
|
|
126
128
|
this.adapter = adapter;
|
|
127
|
-
this._idToken = this.adapter.storage.getItem("idToken");
|
|
128
129
|
if (this.logtoConfig.persistAccessToken) this.loadAccessTokenMap();
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
-
return Boolean(this.
|
|
131
|
+
async isAuthenticated() {
|
|
132
|
+
return Boolean(await this.getIdToken());
|
|
132
133
|
}
|
|
133
|
-
|
|
134
|
-
const jsonItem = this.adapter.storage.getItem("signInSession");
|
|
135
|
-
if (!jsonItem) return null;
|
|
136
|
-
try {
|
|
137
|
-
const item = JSON.parse(jsonItem);
|
|
138
|
-
(0, $4R6L3$superstruct.assert)(item, (0, $6d3989f7f53311af$export$7b65a75f516b80e1));
|
|
139
|
-
return item;
|
|
140
|
-
} catch (error) {
|
|
141
|
-
throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
set signInSession(logtoSignInSessionItem) {
|
|
145
|
-
if (!logtoSignInSessionItem) {
|
|
146
|
-
this.adapter.storage.removeItem("signInSession");
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
150
|
-
this.adapter.storage.setItem("signInSession", jsonItem);
|
|
151
|
-
}
|
|
152
|
-
get refreshToken() {
|
|
134
|
+
async getRefreshToken() {
|
|
153
135
|
return this.adapter.storage.getItem("refreshToken");
|
|
154
136
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.adapter.storage.removeItem("refreshToken");
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
this.adapter.storage.setItem("refreshToken", refreshToken);
|
|
161
|
-
}
|
|
162
|
-
get idToken() {
|
|
163
|
-
return this._idToken;
|
|
164
|
-
}
|
|
165
|
-
set idToken(idToken) {
|
|
166
|
-
this._idToken = idToken;
|
|
167
|
-
if (!idToken) {
|
|
168
|
-
this.adapter.storage.removeItem("idToken");
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
this.adapter.storage.setItem("idToken", idToken);
|
|
137
|
+
async getIdToken() {
|
|
138
|
+
return this.adapter.storage.getItem("idToken");
|
|
172
139
|
}
|
|
173
140
|
// eslint-disable-next-line complexity
|
|
174
141
|
async getAccessToken(resource) {
|
|
175
|
-
if (!this.
|
|
142
|
+
if (!await this.getIdToken()) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("not_authenticated");
|
|
176
143
|
const accessTokenKey = (0, $e2aabdbdb3cc09f0$export$8f595bd2a47bcea6)(resource);
|
|
177
144
|
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
178
145
|
if (accessToken && accessToken.expiresAt > Date.now() / 1000) return accessToken.token;
|
|
@@ -193,9 +160,10 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
193
160
|
this.getAccessTokenPromiseMap.delete(accessTokenKey);
|
|
194
161
|
return token;
|
|
195
162
|
}
|
|
196
|
-
getIdTokenClaims() {
|
|
197
|
-
|
|
198
|
-
|
|
163
|
+
async getIdTokenClaims() {
|
|
164
|
+
const idToken = await this.getIdToken();
|
|
165
|
+
if (!idToken) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("not_authenticated");
|
|
166
|
+
return (0, $4R6L3$logtojs.decodeIdToken)(idToken);
|
|
199
167
|
}
|
|
200
168
|
async signIn(redirectUri) {
|
|
201
169
|
const { appId: clientId , prompt: prompt , resources: resources , scopes: scopes } = this.logtoConfig;
|
|
@@ -213,25 +181,26 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
213
181
|
resources: resources,
|
|
214
182
|
prompt: prompt
|
|
215
183
|
});
|
|
216
|
-
this.
|
|
184
|
+
await this.setSignInSession({
|
|
217
185
|
redirectUri: redirectUri,
|
|
218
186
|
codeVerifier: codeVerifier,
|
|
219
187
|
state: state
|
|
220
|
-
};
|
|
221
|
-
this.
|
|
222
|
-
this.
|
|
188
|
+
});
|
|
189
|
+
await this.setRefreshToken(null);
|
|
190
|
+
await this.setIdToken(null);
|
|
223
191
|
this.adapter.navigate(signInUri);
|
|
224
192
|
}
|
|
225
|
-
isSignInRedirected(url) {
|
|
226
|
-
const
|
|
193
|
+
async isSignInRedirected(url) {
|
|
194
|
+
const signInSession = await this.getSignInSession();
|
|
227
195
|
if (!signInSession) return false;
|
|
228
196
|
const { redirectUri: redirectUri } = signInSession;
|
|
229
197
|
const { origin: origin , pathname: pathname } = new URL(url);
|
|
230
198
|
return `${origin}${pathname}` === redirectUri;
|
|
231
199
|
}
|
|
232
200
|
async handleSignInCallback(callbackUri) {
|
|
233
|
-
const {
|
|
201
|
+
const { logtoConfig: logtoConfig , adapter: adapter } = this;
|
|
234
202
|
const { requester: requester } = adapter;
|
|
203
|
+
const signInSession = await this.getSignInSession();
|
|
235
204
|
if (!signInSession) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("sign_in_session.not_found");
|
|
236
205
|
const { redirectUri: redirectUri , state: state , codeVerifier: codeVerifier } = signInSession;
|
|
237
206
|
const code = (0, $4R6L3$logtojs.verifyAndParseCodeFromCallbackUri)(callbackUri, redirectUri, state);
|
|
@@ -245,30 +214,66 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
245
214
|
code: code
|
|
246
215
|
}, requester);
|
|
247
216
|
await this.verifyIdToken(codeTokenResponse.idToken);
|
|
248
|
-
this.saveCodeToken(codeTokenResponse);
|
|
249
|
-
this.
|
|
217
|
+
await this.saveCodeToken(codeTokenResponse);
|
|
218
|
+
await this.setSignInSession(null);
|
|
250
219
|
}
|
|
251
220
|
async signOut(postLogoutRedirectUri) {
|
|
252
|
-
|
|
221
|
+
const idToken = await this.getIdToken();
|
|
222
|
+
if (!idToken) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("not_authenticated");
|
|
253
223
|
const { appId: clientId } = this.logtoConfig;
|
|
254
224
|
const { endSessionEndpoint: endSessionEndpoint , revocationEndpoint: revocationEndpoint } = await this.getOidcConfig();
|
|
255
|
-
|
|
256
|
-
|
|
225
|
+
const refreshToken = await this.getRefreshToken();
|
|
226
|
+
if (refreshToken) try {
|
|
227
|
+
await (0, $4R6L3$logtojs.revoke)(revocationEndpoint, clientId, refreshToken, this.adapter.requester);
|
|
257
228
|
} catch {
|
|
258
229
|
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
259
230
|
}
|
|
260
231
|
const url = (0, $4R6L3$logtojs.generateSignOutUri)({
|
|
261
232
|
endSessionEndpoint: endSessionEndpoint,
|
|
262
233
|
postLogoutRedirectUri: postLogoutRedirectUri,
|
|
263
|
-
idToken:
|
|
234
|
+
idToken: idToken
|
|
264
235
|
});
|
|
265
236
|
this.accessTokenMap.clear();
|
|
266
|
-
this.
|
|
267
|
-
this.
|
|
237
|
+
await this.setRefreshToken(null);
|
|
238
|
+
await this.setIdToken(null);
|
|
268
239
|
this.adapter.navigate(url);
|
|
269
240
|
}
|
|
241
|
+
async getSignInSession() {
|
|
242
|
+
const jsonItem = await this.adapter.storage.getItem("signInSession");
|
|
243
|
+
if (!jsonItem) return null;
|
|
244
|
+
try {
|
|
245
|
+
const item = JSON.parse(jsonItem);
|
|
246
|
+
(0, $4R6L3$superstruct.assert)(item, (0, $6d3989f7f53311af$export$7b65a75f516b80e1));
|
|
247
|
+
return item;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async setSignInSession(logtoSignInSessionItem) {
|
|
253
|
+
if (!logtoSignInSessionItem) {
|
|
254
|
+
await this.adapter.storage.removeItem("signInSession");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
258
|
+
await this.adapter.storage.setItem("signInSession", jsonItem);
|
|
259
|
+
}
|
|
260
|
+
async setIdToken(idToken) {
|
|
261
|
+
if (!idToken) {
|
|
262
|
+
await this.adapter.storage.removeItem("idToken");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
await this.adapter.storage.setItem("idToken", idToken);
|
|
266
|
+
}
|
|
267
|
+
async setRefreshToken(refreshToken) {
|
|
268
|
+
if (!refreshToken) {
|
|
269
|
+
await this.adapter.storage.removeItem("refreshToken");
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
await this.adapter.storage.setItem("refreshToken", refreshToken);
|
|
273
|
+
}
|
|
270
274
|
async getAccessTokenByRefreshToken(resource) {
|
|
271
|
-
|
|
275
|
+
const currentRefreshToken = await this.getRefreshToken();
|
|
276
|
+
if (!currentRefreshToken) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("not_authenticated");
|
|
272
277
|
try {
|
|
273
278
|
const accessTokenKey = (0, $e2aabdbdb3cc09f0$export$8f595bd2a47bcea6)(resource);
|
|
274
279
|
const { appId: clientId } = this.logtoConfig;
|
|
@@ -276,7 +281,7 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
276
281
|
const { accessToken: accessToken , refreshToken: refreshToken , idToken: idToken , scope: scope , expiresIn: expiresIn } = await (0, $4R6L3$logtojs.fetchTokenByRefreshToken)({
|
|
277
282
|
clientId: clientId,
|
|
278
283
|
tokenEndpoint: tokenEndpoint,
|
|
279
|
-
refreshToken:
|
|
284
|
+
refreshToken: currentRefreshToken,
|
|
280
285
|
resource: resource,
|
|
281
286
|
scopes: resource ? [
|
|
282
287
|
"offline_access"
|
|
@@ -287,11 +292,11 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
287
292
|
scope: scope,
|
|
288
293
|
expiresAt: Math.round(Date.now() / 1000) + expiresIn
|
|
289
294
|
});
|
|
290
|
-
this.saveAccessTokenMap();
|
|
291
|
-
this.refreshToken
|
|
295
|
+
await this.saveAccessTokenMap();
|
|
296
|
+
await this.setRefreshToken(refreshToken);
|
|
292
297
|
if (idToken) {
|
|
293
298
|
await this.verifyIdToken(idToken);
|
|
294
|
-
this.idToken
|
|
299
|
+
await this.setIdToken(idToken);
|
|
295
300
|
}
|
|
296
301
|
return accessToken;
|
|
297
302
|
} catch (error) {
|
|
@@ -317,9 +322,9 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
317
322
|
throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("invalid_id_token", error);
|
|
318
323
|
}
|
|
319
324
|
}
|
|
320
|
-
saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
321
|
-
this.refreshToken
|
|
322
|
-
this.idToken
|
|
325
|
+
async saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
326
|
+
await this.setRefreshToken(refreshToken ?? null);
|
|
327
|
+
await this.setIdToken(idToken);
|
|
323
328
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
324
329
|
const accessTokenKey = (0, $e2aabdbdb3cc09f0$export$8f595bd2a47bcea6)();
|
|
325
330
|
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
@@ -328,17 +333,17 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
|
|
|
328
333
|
scope: scope,
|
|
329
334
|
expiresAt: expiresAt
|
|
330
335
|
});
|
|
331
|
-
this.saveAccessTokenMap();
|
|
336
|
+
await this.saveAccessTokenMap();
|
|
332
337
|
}
|
|
333
|
-
saveAccessTokenMap() {
|
|
338
|
+
async saveAccessTokenMap() {
|
|
334
339
|
if (!this.logtoConfig.persistAccessToken) return;
|
|
335
340
|
const data = {};
|
|
336
341
|
for (const [key, accessToken] of this.accessTokenMap.entries())// eslint-disable-next-line @silverhand/fp/no-mutation
|
|
337
342
|
data[key] = accessToken;
|
|
338
|
-
this.adapter.storage.setItem("accessToken", JSON.stringify(data));
|
|
343
|
+
await this.adapter.storage.setItem("accessToken", JSON.stringify(data));
|
|
339
344
|
}
|
|
340
|
-
loadAccessTokenMap() {
|
|
341
|
-
const raw = this.adapter.storage.getItem("accessToken");
|
|
345
|
+
async loadAccessTokenMap() {
|
|
346
|
+
const raw = await this.adapter.storage.getItem("accessToken");
|
|
342
347
|
if (!raw) return;
|
|
343
348
|
try {
|
|
344
349
|
const json = JSON.parse(raw);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n\n protected readonly adapter: ClientAdapter;\n\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n private _idToken: Nullable<string>;\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n this._idToken = this.adapter.storage.getItem('idToken');\n\n if (this.logtoConfig.persistAccessToken) {\n this.loadAccessTokenMap();\n }\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected set signInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n get refreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n get idToken() {\n return this._idToken;\n }\n\n private set idToken(idToken: Nullable<string>) {\n this._idToken = idToken;\n\n if (!idToken) {\n this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n this.adapter.storage.setItem('idToken', idToken);\n }\n\n // eslint-disable-next-line complexity\n public async getAccessToken(resource?: string): Promise<string> {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n public getIdTokenClaims(): IdTokenClaims {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(this.idToken);\n }\n\n public async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n this.signInSession = { redirectUri, codeVerifier, state };\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(signInUri);\n }\n\n public isSignInRedirected(url: string): boolean {\n const { signInSession } = this;\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n public async handleSignInCallback(callbackUri: string) {\n const { signInSession, logtoConfig, adapter } = this;\n const { requester } = adapter;\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n\n this.saveCodeToken(codeTokenResponse);\n this.signInSession = null;\n }\n\n public async signOut(postLogoutRedirectUri?: string) {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n\n if (this.refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, this.refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken: this.idToken,\n });\n\n this.accessTokenMap.clear();\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(url);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n if (!this.refreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: this.refreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n this.saveAccessTokenMap();\n\n this.refreshToken = refreshToken;\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n this.idToken = idToken;\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n this.refreshToken = refreshToken ?? null;\n this.idToken = idToken;\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n this.saveAccessTokenMap();\n }\n\n private saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private loadAccessTokenMap() {\n const raw = this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n","import { NormalizeKeyPaths } from '@silverhand/essentials';\nimport get from 'lodash.get';\n\nconst logtoClientErrorCodes = Object.freeze({\n sign_in_session: {\n invalid: 'Invalid sign-in session.',\n not_found: 'Sign-in session not found.',\n },\n not_authenticated: 'Not authenticated.',\n get_access_token_by_refresh_token_failed: 'Failed to get access token by refresh token.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { Prompt } from '@logto/js';\nimport { Infer, number, record, string, type } from 'superstruct';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n persistAccessToken?: boolean;\n};\n\nexport const AccessTokenSchema = type({\n token: string(),\n scope: string(),\n expiresAt: number(),\n});\n\nexport type AccessToken = Infer<typeof AccessTokenSchema>;\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport const LogtoAccessTokenMapSchema = record(string(), AccessTokenSchema);\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoRequestError, LogtoRequestErrorBody, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n // Expected request error from server\n const { code, message } = await response.json<LogtoRequestErrorBody>();\n throw new LogtoRequestError(code, message);\n }\n\n return response.json<T>();\n };\n};\n"],"names":[],"version":3,"file":"index.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n if (this.logtoConfig.persistAccessToken) {\n void this.loadAccessTokenMap();\n }\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n","import { NormalizeKeyPaths } from '@silverhand/essentials';\nimport get from 'lodash.get';\n\nconst logtoClientErrorCodes = Object.freeze({\n sign_in_session: {\n invalid: 'Invalid sign-in session.',\n not_found: 'Sign-in session not found.',\n },\n not_authenticated: 'Not authenticated.',\n get_access_token_by_refresh_token_failed: 'Failed to get access token by refresh token.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { Prompt } from '@logto/js';\nimport { Infer, number, record, string, type } from 'superstruct';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n persistAccessToken?: boolean;\n};\n\nexport const AccessTokenSchema = type({\n token: string(),\n scope: string(),\n expiresAt: number(),\n});\n\nexport type AccessToken = Infer<typeof AccessTokenSchema>;\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport const LogtoAccessTokenMapSchema = record(string(), AccessTokenSchema);\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoError, LogtoRequestError, logtoRequestErrorSchema, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!logtoRequestErrorSchema.is(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"index.js.map"}
|
package/lib/module.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Prompt as $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908, withReservedScopes as $kqBTI$withReservedScopes, decodeIdToken as $kqBTI$decodeIdToken, generateSignInUri as $kqBTI$generateSignInUri, verifyAndParseCodeFromCallbackUri as $kqBTI$verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode as $kqBTI$fetchTokenByAuthorizationCode, revoke as $kqBTI$revoke, generateSignOutUri as $kqBTI$generateSignOutUri, fetchTokenByRefreshToken as $kqBTI$fetchTokenByRefreshToken, fetchOidcConfig as $kqBTI$fetchOidcConfig, verifyIdToken as $kqBTI$verifyIdToken, LogtoError as $19775a679e2952df$re_export$LogtoError, OidcError as $19775a679e2952df$re_export$OidcError, LogtoRequestError as $19775a679e2952df$re_export$LogtoRequestError, discoveryPath as $kqBTI$discoveryPath} from "@logto/js";
|
|
1
|
+
import {Prompt as $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908, withReservedScopes as $kqBTI$withReservedScopes, decodeIdToken as $kqBTI$decodeIdToken, generateSignInUri as $kqBTI$generateSignInUri, verifyAndParseCodeFromCallbackUri as $kqBTI$verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode as $kqBTI$fetchTokenByAuthorizationCode, revoke as $kqBTI$revoke, generateSignOutUri as $kqBTI$generateSignOutUri, fetchTokenByRefreshToken as $kqBTI$fetchTokenByRefreshToken, fetchOidcConfig as $kqBTI$fetchOidcConfig, verifyIdToken as $kqBTI$verifyIdToken, LogtoError as $19775a679e2952df$re_export$LogtoError, OidcError as $19775a679e2952df$re_export$OidcError, LogtoRequestError as $19775a679e2952df$re_export$LogtoRequestError, discoveryPath as $kqBTI$discoveryPath, logtoRequestErrorSchema as $kqBTI$logtoRequestErrorSchema} from "@logto/js";
|
|
2
2
|
import {createRemoteJWKSet as $kqBTI$createRemoteJWKSet} from "jose";
|
|
3
3
|
import $kqBTI$lodashonce from "lodash.once";
|
|
4
4
|
import {assert as $kqBTI$assert, type as $kqBTI$type, string as $kqBTI$string, number as $kqBTI$number, record as $kqBTI$record} from "superstruct";
|
|
@@ -64,8 +64,10 @@ const $8449a5dbad0d6387$export$8d54726fdbf08e0a = (fetchFunction)=>{
|
|
|
64
64
|
return async (...args)=>{
|
|
65
65
|
const response = await fetchFunction(...args);
|
|
66
66
|
if (!response.ok) {
|
|
67
|
+
const responseJson = await response.json();
|
|
68
|
+
if (!(0, $kqBTI$logtoRequestErrorSchema).is(responseJson)) throw new (0, $19775a679e2952df$re_export$LogtoError)("unexpected_response_error", responseJson);
|
|
67
69
|
// Expected request error from server
|
|
68
|
-
const { code: code , message: message } =
|
|
70
|
+
const { code: code , message: message } = responseJson;
|
|
69
71
|
throw new (0, $19775a679e2952df$re_export$LogtoRequestError)(code, message);
|
|
70
72
|
}
|
|
71
73
|
return response.json();
|
|
@@ -93,55 +95,20 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
93
95
|
scopes: (0, $kqBTI$withReservedScopes)(logtoConfig.scopes).split(" ")
|
|
94
96
|
};
|
|
95
97
|
this.adapter = adapter;
|
|
96
|
-
this._idToken = this.adapter.storage.getItem("idToken");
|
|
97
98
|
if (this.logtoConfig.persistAccessToken) this.loadAccessTokenMap();
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
-
return Boolean(this.
|
|
100
|
+
async isAuthenticated() {
|
|
101
|
+
return Boolean(await this.getIdToken());
|
|
101
102
|
}
|
|
102
|
-
|
|
103
|
-
const jsonItem = this.adapter.storage.getItem("signInSession");
|
|
104
|
-
if (!jsonItem) return null;
|
|
105
|
-
try {
|
|
106
|
-
const item = JSON.parse(jsonItem);
|
|
107
|
-
(0, $kqBTI$assert)(item, (0, $50f2bb780a45e70c$export$7b65a75f516b80e1));
|
|
108
|
-
return item;
|
|
109
|
-
} catch (error) {
|
|
110
|
-
throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
set signInSession(logtoSignInSessionItem) {
|
|
114
|
-
if (!logtoSignInSessionItem) {
|
|
115
|
-
this.adapter.storage.removeItem("signInSession");
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
119
|
-
this.adapter.storage.setItem("signInSession", jsonItem);
|
|
120
|
-
}
|
|
121
|
-
get refreshToken() {
|
|
103
|
+
async getRefreshToken() {
|
|
122
104
|
return this.adapter.storage.getItem("refreshToken");
|
|
123
105
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.adapter.storage.removeItem("refreshToken");
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
this.adapter.storage.setItem("refreshToken", refreshToken);
|
|
130
|
-
}
|
|
131
|
-
get idToken() {
|
|
132
|
-
return this._idToken;
|
|
133
|
-
}
|
|
134
|
-
set idToken(idToken) {
|
|
135
|
-
this._idToken = idToken;
|
|
136
|
-
if (!idToken) {
|
|
137
|
-
this.adapter.storage.removeItem("idToken");
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
this.adapter.storage.setItem("idToken", idToken);
|
|
106
|
+
async getIdToken() {
|
|
107
|
+
return this.adapter.storage.getItem("idToken");
|
|
141
108
|
}
|
|
142
109
|
// eslint-disable-next-line complexity
|
|
143
110
|
async getAccessToken(resource) {
|
|
144
|
-
if (!this.
|
|
111
|
+
if (!await this.getIdToken()) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("not_authenticated");
|
|
145
112
|
const accessTokenKey = (0, $dcfd5d64758ae70b$export$8f595bd2a47bcea6)(resource);
|
|
146
113
|
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
147
114
|
if (accessToken && accessToken.expiresAt > Date.now() / 1000) return accessToken.token;
|
|
@@ -162,9 +129,10 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
162
129
|
this.getAccessTokenPromiseMap.delete(accessTokenKey);
|
|
163
130
|
return token;
|
|
164
131
|
}
|
|
165
|
-
getIdTokenClaims() {
|
|
166
|
-
|
|
167
|
-
|
|
132
|
+
async getIdTokenClaims() {
|
|
133
|
+
const idToken = await this.getIdToken();
|
|
134
|
+
if (!idToken) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("not_authenticated");
|
|
135
|
+
return (0, $kqBTI$decodeIdToken)(idToken);
|
|
168
136
|
}
|
|
169
137
|
async signIn(redirectUri) {
|
|
170
138
|
const { appId: clientId , prompt: prompt , resources: resources , scopes: scopes } = this.logtoConfig;
|
|
@@ -182,25 +150,26 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
182
150
|
resources: resources,
|
|
183
151
|
prompt: prompt
|
|
184
152
|
});
|
|
185
|
-
this.
|
|
153
|
+
await this.setSignInSession({
|
|
186
154
|
redirectUri: redirectUri,
|
|
187
155
|
codeVerifier: codeVerifier,
|
|
188
156
|
state: state
|
|
189
|
-
};
|
|
190
|
-
this.
|
|
191
|
-
this.
|
|
157
|
+
});
|
|
158
|
+
await this.setRefreshToken(null);
|
|
159
|
+
await this.setIdToken(null);
|
|
192
160
|
this.adapter.navigate(signInUri);
|
|
193
161
|
}
|
|
194
|
-
isSignInRedirected(url) {
|
|
195
|
-
const
|
|
162
|
+
async isSignInRedirected(url) {
|
|
163
|
+
const signInSession = await this.getSignInSession();
|
|
196
164
|
if (!signInSession) return false;
|
|
197
165
|
const { redirectUri: redirectUri } = signInSession;
|
|
198
166
|
const { origin: origin , pathname: pathname } = new URL(url);
|
|
199
167
|
return `${origin}${pathname}` === redirectUri;
|
|
200
168
|
}
|
|
201
169
|
async handleSignInCallback(callbackUri) {
|
|
202
|
-
const {
|
|
170
|
+
const { logtoConfig: logtoConfig , adapter: adapter } = this;
|
|
203
171
|
const { requester: requester } = adapter;
|
|
172
|
+
const signInSession = await this.getSignInSession();
|
|
204
173
|
if (!signInSession) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("sign_in_session.not_found");
|
|
205
174
|
const { redirectUri: redirectUri , state: state , codeVerifier: codeVerifier } = signInSession;
|
|
206
175
|
const code = (0, $kqBTI$verifyAndParseCodeFromCallbackUri)(callbackUri, redirectUri, state);
|
|
@@ -214,30 +183,66 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
214
183
|
code: code
|
|
215
184
|
}, requester);
|
|
216
185
|
await this.verifyIdToken(codeTokenResponse.idToken);
|
|
217
|
-
this.saveCodeToken(codeTokenResponse);
|
|
218
|
-
this.
|
|
186
|
+
await this.saveCodeToken(codeTokenResponse);
|
|
187
|
+
await this.setSignInSession(null);
|
|
219
188
|
}
|
|
220
189
|
async signOut(postLogoutRedirectUri) {
|
|
221
|
-
|
|
190
|
+
const idToken = await this.getIdToken();
|
|
191
|
+
if (!idToken) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("not_authenticated");
|
|
222
192
|
const { appId: clientId } = this.logtoConfig;
|
|
223
193
|
const { endSessionEndpoint: endSessionEndpoint , revocationEndpoint: revocationEndpoint } = await this.getOidcConfig();
|
|
224
|
-
|
|
225
|
-
|
|
194
|
+
const refreshToken = await this.getRefreshToken();
|
|
195
|
+
if (refreshToken) try {
|
|
196
|
+
await (0, $kqBTI$revoke)(revocationEndpoint, clientId, refreshToken, this.adapter.requester);
|
|
226
197
|
} catch {
|
|
227
198
|
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
228
199
|
}
|
|
229
200
|
const url = (0, $kqBTI$generateSignOutUri)({
|
|
230
201
|
endSessionEndpoint: endSessionEndpoint,
|
|
231
202
|
postLogoutRedirectUri: postLogoutRedirectUri,
|
|
232
|
-
idToken:
|
|
203
|
+
idToken: idToken
|
|
233
204
|
});
|
|
234
205
|
this.accessTokenMap.clear();
|
|
235
|
-
this.
|
|
236
|
-
this.
|
|
206
|
+
await this.setRefreshToken(null);
|
|
207
|
+
await this.setIdToken(null);
|
|
237
208
|
this.adapter.navigate(url);
|
|
238
209
|
}
|
|
210
|
+
async getSignInSession() {
|
|
211
|
+
const jsonItem = await this.adapter.storage.getItem("signInSession");
|
|
212
|
+
if (!jsonItem) return null;
|
|
213
|
+
try {
|
|
214
|
+
const item = JSON.parse(jsonItem);
|
|
215
|
+
(0, $kqBTI$assert)(item, (0, $50f2bb780a45e70c$export$7b65a75f516b80e1));
|
|
216
|
+
return item;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async setSignInSession(logtoSignInSessionItem) {
|
|
222
|
+
if (!logtoSignInSessionItem) {
|
|
223
|
+
await this.adapter.storage.removeItem("signInSession");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
227
|
+
await this.adapter.storage.setItem("signInSession", jsonItem);
|
|
228
|
+
}
|
|
229
|
+
async setIdToken(idToken) {
|
|
230
|
+
if (!idToken) {
|
|
231
|
+
await this.adapter.storage.removeItem("idToken");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
await this.adapter.storage.setItem("idToken", idToken);
|
|
235
|
+
}
|
|
236
|
+
async setRefreshToken(refreshToken) {
|
|
237
|
+
if (!refreshToken) {
|
|
238
|
+
await this.adapter.storage.removeItem("refreshToken");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
await this.adapter.storage.setItem("refreshToken", refreshToken);
|
|
242
|
+
}
|
|
239
243
|
async getAccessTokenByRefreshToken(resource) {
|
|
240
|
-
|
|
244
|
+
const currentRefreshToken = await this.getRefreshToken();
|
|
245
|
+
if (!currentRefreshToken) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("not_authenticated");
|
|
241
246
|
try {
|
|
242
247
|
const accessTokenKey = (0, $dcfd5d64758ae70b$export$8f595bd2a47bcea6)(resource);
|
|
243
248
|
const { appId: clientId } = this.logtoConfig;
|
|
@@ -245,7 +250,7 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
245
250
|
const { accessToken: accessToken , refreshToken: refreshToken , idToken: idToken , scope: scope , expiresIn: expiresIn } = await (0, $kqBTI$fetchTokenByRefreshToken)({
|
|
246
251
|
clientId: clientId,
|
|
247
252
|
tokenEndpoint: tokenEndpoint,
|
|
248
|
-
refreshToken:
|
|
253
|
+
refreshToken: currentRefreshToken,
|
|
249
254
|
resource: resource,
|
|
250
255
|
scopes: resource ? [
|
|
251
256
|
"offline_access"
|
|
@@ -256,11 +261,11 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
256
261
|
scope: scope,
|
|
257
262
|
expiresAt: Math.round(Date.now() / 1000) + expiresIn
|
|
258
263
|
});
|
|
259
|
-
this.saveAccessTokenMap();
|
|
260
|
-
this.refreshToken
|
|
264
|
+
await this.saveAccessTokenMap();
|
|
265
|
+
await this.setRefreshToken(refreshToken);
|
|
261
266
|
if (idToken) {
|
|
262
267
|
await this.verifyIdToken(idToken);
|
|
263
|
-
this.idToken
|
|
268
|
+
await this.setIdToken(idToken);
|
|
264
269
|
}
|
|
265
270
|
return accessToken;
|
|
266
271
|
} catch (error) {
|
|
@@ -286,9 +291,9 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
286
291
|
throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("invalid_id_token", error);
|
|
287
292
|
}
|
|
288
293
|
}
|
|
289
|
-
saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
290
|
-
this.refreshToken
|
|
291
|
-
this.idToken
|
|
294
|
+
async saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
295
|
+
await this.setRefreshToken(refreshToken ?? null);
|
|
296
|
+
await this.setIdToken(idToken);
|
|
292
297
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
293
298
|
const accessTokenKey = (0, $dcfd5d64758ae70b$export$8f595bd2a47bcea6)();
|
|
294
299
|
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
@@ -297,17 +302,17 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
|
|
|
297
302
|
scope: scope,
|
|
298
303
|
expiresAt: expiresAt
|
|
299
304
|
});
|
|
300
|
-
this.saveAccessTokenMap();
|
|
305
|
+
await this.saveAccessTokenMap();
|
|
301
306
|
}
|
|
302
|
-
saveAccessTokenMap() {
|
|
307
|
+
async saveAccessTokenMap() {
|
|
303
308
|
if (!this.logtoConfig.persistAccessToken) return;
|
|
304
309
|
const data = {};
|
|
305
310
|
for (const [key, accessToken] of this.accessTokenMap.entries())// eslint-disable-next-line @silverhand/fp/no-mutation
|
|
306
311
|
data[key] = accessToken;
|
|
307
|
-
this.adapter.storage.setItem("accessToken", JSON.stringify(data));
|
|
312
|
+
await this.adapter.storage.setItem("accessToken", JSON.stringify(data));
|
|
308
313
|
}
|
|
309
|
-
loadAccessTokenMap() {
|
|
310
|
-
const raw = this.adapter.storage.getItem("accessToken");
|
|
314
|
+
async loadAccessTokenMap() {
|
|
315
|
+
const raw = await this.adapter.storage.getItem("accessToken");
|
|
311
316
|
if (!raw) return;
|
|
312
317
|
try {
|
|
313
318
|
const json = JSON.parse(raw);
|
package/lib/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n\n protected readonly adapter: ClientAdapter;\n\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n private _idToken: Nullable<string>;\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n this._idToken = this.adapter.storage.getItem('idToken');\n\n if (this.logtoConfig.persistAccessToken) {\n this.loadAccessTokenMap();\n }\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected set signInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n get refreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n get idToken() {\n return this._idToken;\n }\n\n private set idToken(idToken: Nullable<string>) {\n this._idToken = idToken;\n\n if (!idToken) {\n this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n this.adapter.storage.setItem('idToken', idToken);\n }\n\n // eslint-disable-next-line complexity\n public async getAccessToken(resource?: string): Promise<string> {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n public getIdTokenClaims(): IdTokenClaims {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(this.idToken);\n }\n\n public async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n this.signInSession = { redirectUri, codeVerifier, state };\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(signInUri);\n }\n\n public isSignInRedirected(url: string): boolean {\n const { signInSession } = this;\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n public async handleSignInCallback(callbackUri: string) {\n const { signInSession, logtoConfig, adapter } = this;\n const { requester } = adapter;\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n\n this.saveCodeToken(codeTokenResponse);\n this.signInSession = null;\n }\n\n public async signOut(postLogoutRedirectUri?: string) {\n if (!this.idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n\n if (this.refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, this.refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken: this.idToken,\n });\n\n this.accessTokenMap.clear();\n this.refreshToken = null;\n this.idToken = null;\n\n this.adapter.navigate(url);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n if (!this.refreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: this.refreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n this.saveAccessTokenMap();\n\n this.refreshToken = refreshToken;\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n this.idToken = idToken;\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n this.refreshToken = refreshToken ?? null;\n this.idToken = idToken;\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n this.saveAccessTokenMap();\n }\n\n private saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private loadAccessTokenMap() {\n const raw = this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n","import { NormalizeKeyPaths } from '@silverhand/essentials';\nimport get from 'lodash.get';\n\nconst logtoClientErrorCodes = Object.freeze({\n sign_in_session: {\n invalid: 'Invalid sign-in session.',\n not_found: 'Sign-in session not found.',\n },\n not_authenticated: 'Not authenticated.',\n get_access_token_by_refresh_token_failed: 'Failed to get access token by refresh token.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { Prompt } from '@logto/js';\nimport { Infer, number, record, string, type } from 'superstruct';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n persistAccessToken?: boolean;\n};\n\nexport const AccessTokenSchema = type({\n token: string(),\n scope: string(),\n expiresAt: number(),\n});\n\nexport type AccessToken = Infer<typeof AccessTokenSchema>;\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport const LogtoAccessTokenMapSchema = record(string(), AccessTokenSchema);\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoRequestError, LogtoRequestErrorBody, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n // Expected request error from server\n const { code, message } = await response.json<LogtoRequestErrorBody>();\n throw new LogtoRequestError(code, message);\n }\n\n return response.json<T>();\n };\n};\n"],"names":[],"version":3,"file":"module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withReservedScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\nimport { assert } from 'superstruct';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n LogtoAccessTokenMapSchema,\n LogtoConfig,\n LogtoSignInSessionItem,\n LogtoSignInSessionItemSchema,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n if (this.logtoConfig.persistAccessToken) {\n void this.loadAccessTokenMap();\n }\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n try {\n const item: unknown = JSON.parse(jsonItem);\n assert(item, LogtoSignInSessionItemSchema);\n\n return item;\n } catch (error: unknown) {\n throw new LogtoClientError('sign_in_session.invalid', error);\n }\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? ['offline_access'] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n if (!this.logtoConfig.persistAccessToken) {\n return;\n }\n\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n assert(json, LogtoAccessTokenMapSchema);\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n","import { NormalizeKeyPaths } from '@silverhand/essentials';\nimport get from 'lodash.get';\n\nconst logtoClientErrorCodes = Object.freeze({\n sign_in_session: {\n invalid: 'Invalid sign-in session.',\n not_found: 'Sign-in session not found.',\n },\n not_authenticated: 'Not authenticated.',\n get_access_token_by_refresh_token_failed: 'Failed to get access token by refresh token.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { Prompt } from '@logto/js';\nimport { Infer, number, record, string, type } from 'superstruct';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n persistAccessToken?: boolean;\n};\n\nexport const AccessTokenSchema = type({\n token: string(),\n scope: string(),\n expiresAt: number(),\n});\n\nexport type AccessToken = Infer<typeof AccessTokenSchema>;\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport const LogtoAccessTokenMapSchema = record(string(), AccessTokenSchema);\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoError, LogtoRequestError, logtoRequestErrorSchema, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!logtoRequestErrorSchema.is(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/client",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"source": "./src/index.ts",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepack": "pnpm test"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@logto/js": "^1.0.0-beta.
|
|
33
|
-
"@silverhand/essentials": "^1.
|
|
32
|
+
"@logto/js": "^1.0.0-beta.4",
|
|
33
|
+
"@silverhand/essentials": "^1.2.0",
|
|
34
34
|
"camelcase-keys": "^7.0.1",
|
|
35
35
|
"jose": "^4.3.8",
|
|
36
36
|
"lodash.get": "^4.4.2",
|
|
@@ -39,26 +39,26 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@jest/types": "^27.5.1",
|
|
42
|
-
"@parcel/core": "^2.
|
|
43
|
-
"@parcel/packager-ts": "^2.
|
|
44
|
-
"@parcel/transformer-typescript-types": "^2.
|
|
45
|
-
"@silverhand/eslint-config": "^0.
|
|
46
|
-
"@silverhand/ts-config": "^0.
|
|
42
|
+
"@parcel/core": "^2.7.0",
|
|
43
|
+
"@parcel/packager-ts": "^2.7.0",
|
|
44
|
+
"@parcel/transformer-typescript-types": "^2.7.0",
|
|
45
|
+
"@silverhand/eslint-config": "^1.0.0",
|
|
46
|
+
"@silverhand/ts-config": "^1.0.0",
|
|
47
47
|
"@types/jest": "^27.4.1",
|
|
48
48
|
"@types/lodash.get": "^4.4.6",
|
|
49
49
|
"@types/lodash.once": "^4.1.7",
|
|
50
50
|
"@types/node": "^17.0.19",
|
|
51
|
-
"eslint": "^8.
|
|
51
|
+
"eslint": "^8.23.0",
|
|
52
52
|
"jest": "^27.5.1",
|
|
53
53
|
"jest-matcher-specific-error": "^1.0.0",
|
|
54
54
|
"lint-staged": "^13.0.0",
|
|
55
55
|
"nock": "^13.1.3",
|
|
56
|
-
"parcel": "^2.
|
|
57
|
-
"prettier": "^2.
|
|
56
|
+
"parcel": "^2.7.0",
|
|
57
|
+
"prettier": "^2.7.1",
|
|
58
58
|
"text-encoder": "^0.0.4",
|
|
59
59
|
"ts-jest": "^27.0.4",
|
|
60
60
|
"type-fest": "^2.10.0",
|
|
61
|
-
"typescript": "
|
|
61
|
+
"typescript": "4.7.4"
|
|
62
62
|
},
|
|
63
63
|
"eslintConfig": {
|
|
64
64
|
"extends": "@silverhand"
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"access": "public"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "8b0f8947ac211fd8d4b6e2e00ce6acfc9dd344db"
|
|
71
71
|
}
|