@logto/browser 1.0.0-alpha.2 → 1.0.0-beta.10
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 +45 -0
- package/lib/index.d.ts +5 -64
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +59 -279
- package/lib/index.js.map +1 -1
- package/lib/module.js +54 -263
- package/lib/module.js.map +1 -1
- package/package.json +15 -19
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Logto JS (Core) SDK
|
|
2
|
+
[](https://www.npmjs.com/package/@logto/js)
|
|
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 Core SDK written in TypeScript. Check out our [docs](https://docs.logto.io/JavaScript/browser/) for more information.
|
|
7
|
+
|
|
8
|
+
We also provide [文档](https://docs.logto.io/zh-cn/sdk/JavaScript/browser/) in Simplified Chinese.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
### Using npm
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @logto/browser
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Using yarn
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
yarn add @logto/browser
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Using pnpm
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @logto/browser
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## What is this and how does it work?
|
|
31
|
+
|
|
32
|
+
As the name suggests, Logto browser SDK is the foundation of all Logto SDKs that run in a browser environment (Vanilla, React, Vue, etc.). `@logto/browser` extends `@logto/client` and provides a browser specific implementation of the client adapters:
|
|
33
|
+
|
|
34
|
+
* Implements `Storage` by using browser `localStorage` and `sessionStorage`.
|
|
35
|
+
* Implements `navigate` method by using `window.location.href`.
|
|
36
|
+
|
|
37
|
+
Usually you are not expected to use it directly in your application, but instead choosing a framework specific SDK that built on top of it. We have already released a set of official SDKs to accelerate your integration. [Check this out](https://docs.logto.io/docs/recipes/integrate-logto/) and get started!
|
|
38
|
+
|
|
39
|
+
If Logto does not support your front-end framework and you want to create your own SDK from scratch, we recommend checking out the SDK specification first. You can also refer to our [React SDK](https://github.com/logto-io/js/tree/master/packages/react) and [Vue SDK](https://github.com/logto-io/js/tree/master/packages/react) to learn more about the implementation details.
|
|
40
|
+
|
|
41
|
+
## Resources
|
|
42
|
+
|
|
43
|
+
[](https://logto.io/)
|
|
44
|
+
[](https://docs.logto.io/sdk/JavaScript/browser/)
|
|
45
|
+
[](https://discord.gg/UEPaF3j5e6)
|
package/lib/index.d.ts
CHANGED
|
@@ -1,67 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
invalid: string;
|
|
7
|
-
not_found: string;
|
|
8
|
-
};
|
|
9
|
-
not_authenticated: string;
|
|
10
|
-
get_access_token_by_refresh_token_failed: string;
|
|
11
|
-
invalid_id_token: string;
|
|
12
|
-
}>;
|
|
13
|
-
export type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;
|
|
14
|
-
export class LogtoClientError extends Error {
|
|
15
|
-
code: LogtoClientErrorCode;
|
|
16
|
-
data: unknown;
|
|
17
|
-
constructor(code: LogtoClientErrorCode, data?: unknown);
|
|
18
|
-
}
|
|
19
|
-
export type { IdTokenClaims, LogtoErrorCode } from '@logto/js';
|
|
20
|
-
export { LogtoError, OidcError, Prompt } from '@logto/js';
|
|
21
|
-
export type LogtoConfig = {
|
|
22
|
-
endpoint: string;
|
|
23
|
-
appId: string;
|
|
24
|
-
scopes?: string[];
|
|
25
|
-
resources?: string[];
|
|
26
|
-
prompt?: Prompt;
|
|
27
|
-
usingPersistStorage?: boolean;
|
|
28
|
-
};
|
|
29
|
-
export type AccessToken = {
|
|
30
|
-
token: string;
|
|
31
|
-
scope: string;
|
|
32
|
-
expiresAt: number;
|
|
33
|
-
};
|
|
34
|
-
export const LogtoSignInSessionItemSchema: import("superstruct").Struct<{
|
|
35
|
-
redirectUri: string;
|
|
36
|
-
codeVerifier: string;
|
|
37
|
-
state: string;
|
|
38
|
-
}, {
|
|
39
|
-
redirectUri: import("superstruct").Struct<string, null>;
|
|
40
|
-
codeVerifier: import("superstruct").Struct<string, null>;
|
|
41
|
-
state: import("superstruct").Struct<string, null>;
|
|
42
|
-
}>;
|
|
43
|
-
export type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;
|
|
44
|
-
export default class LogtoClient {
|
|
45
|
-
protected readonly logtoConfig: LogtoConfig;
|
|
46
|
-
protected readonly getOidcConfig: () => Promise<import("@silverhand/essentials").KeysToCamelCase<import("@logto/js").OidcConfigSnakeCaseResponse>>;
|
|
47
|
-
protected readonly getJwtVerifyGetKey: () => Promise<import("jose/dist/types/types").GetKeyFunction<import("jose").JWSHeaderParameters, import("jose").FlattenedJWSInput>>;
|
|
48
|
-
protected readonly logtoStorageKey: string;
|
|
49
|
-
protected readonly requester: Requester;
|
|
50
|
-
protected readonly accessTokenMap: Map<string, AccessToken>;
|
|
51
|
-
constructor(logtoConfig: LogtoConfig, requester?: <T>(input: RequestInfo, init?: RequestInit | undefined) => Promise<T>);
|
|
52
|
-
get isAuthenticated(): boolean;
|
|
53
|
-
protected get signInSession(): Nullable<LogtoSignInSessionItem>;
|
|
54
|
-
protected set signInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>);
|
|
55
|
-
get refreshToken(): Nullable<string>;
|
|
56
|
-
private set refreshToken(value);
|
|
57
|
-
get idToken(): Nullable<string>;
|
|
58
|
-
private set idToken(value);
|
|
59
|
-
getAccessToken(resource?: string): Promise<string>;
|
|
60
|
-
getIdTokenClaims(): IdTokenClaims;
|
|
61
|
-
signIn(redirectUri: string): Promise<void>;
|
|
62
|
-
isSignInRedirected(url: string): boolean;
|
|
63
|
-
handleSignInCallback(callbackUri: string): Promise<void>;
|
|
64
|
-
signOut(postLogoutRedirectUri?: string): Promise<void>;
|
|
1
|
+
import BaseClient, { LogtoConfig } from "@logto/client";
|
|
2
|
+
export type { IdTokenClaims, LogtoErrorCode, LogtoConfig, LogtoClientErrorCode, UserInfoResponse, } from '@logto/client';
|
|
3
|
+
export { LogtoError, OidcError, Prompt, LogtoRequestError, LogtoClientError, ReservedScope, UserScope, } from '@logto/client';
|
|
4
|
+
export default class LogtoClient extends BaseClient {
|
|
5
|
+
constructor(config: LogtoConfig);
|
|
65
6
|
}
|
|
66
7
|
|
|
67
8
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;AAGA,QAAA,MAAM;;;;;;;;EAQJ,CAAC;AAEH,mCAAmC,kBAAkB,4BAA4B,CAAC,CAAC;AAcnF,6BAA8B,SAAQ,KAAK;IACzC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;gBAEF,IAAI,EAAE,oBAAoB,EAAE,IAAI,CAAC,EAAE,OAAO;CAKvD;AEFD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAG1D,0BAA0B;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,0BAA0B;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,OAAO,MAAM;;;;;;;;EAIX,CAAC;AAEH,qCAAqC,MAAM,mCAAmC,CAAC,CAAC;AAEhF;IACE,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,aAAa,mHAA6B;IAC7D,SAAS,CAAC,QAAQ,CAAC,kBAAkB,sIAAkC;IAEvE,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAExC,SAAS,CAAC,QAAQ,CAAC,cAAc,2BAAkC;gBAKvD,WAAW,EAAE,WAAW,EAAE,SAAS,wEAAoB;IAWnE,IAAW,eAAe,YAEzB;IAED,SAAS,KAAK,aAAa,IAAI,SAAS,sBAAsB,CAAC,CAe9D;IAED,SAAS,KAAK,aAAa,CAAC,sBAAsB,EAAE,SAAS,sBAAsB,CAAC,EASnF;IAED,IAAI,YAAY,IAIuB,SAAS,MAAM,CAAC,CAFtD;IAED,OAAO,KAAK,YAAY,QAUvB;IAED,IAAI,OAAO,IAIkB,SAAS,MAAM,CAAC,CAF5C;IAED,OAAO,KAAK,OAAO,QAYlB;IAGY,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyCxD,gBAAgB,IAAI,aAAa;IAQ3B,MAAM,CAAC,WAAW,EAAE,MAAM;IAyBhC,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAYlC,oBAAoB,CAAC,WAAW,EAAE,MAAM;IA6BxC,OAAO,CAAC,qBAAqB,CAAC,EAAE,MAAM;CA6GpD","sources":["packages/browser/src/src/errors.ts","packages/browser/src/src/utils/index.ts","packages/browser/src/src/index.ts","packages/browser/src/index.ts"],"sourcesContent":[null,null,null,"import {\n CodeTokenResponse,\n createRequester,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateCodeChallenge,\n generateCodeVerifier,\n generateSignInUri,\n generateSignOutUri,\n generateState,\n IdTokenClaims,\n Prompt,\n Requester,\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, Infer, string, type } from 'superstruct';\n\nimport { LogtoClientError } from './errors';\nimport {\n buildAccessTokenKey,\n buildIdTokenKey,\n buildLogtoKey,\n buildRefreshTokenKey,\n getDiscoveryEndpoint,\n} from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt } from '@logto/js';\nexport * from './errors';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n usingPersistStorage?: boolean;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number; // Unix Timestamp in seconds\n};\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\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 logtoStorageKey: string;\n protected readonly requester: Requester;\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, requester = createRequester()) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.logtoStorageKey = buildLogtoKey(logtoConfig.appId);\n this.requester = requester;\n this._idToken = localStorage.getItem(buildIdTokenKey(this.logtoStorageKey));\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = sessionStorage.getItem(this.logtoStorageKey);\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 sessionStorage.removeItem(this.logtoStorageKey);\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n sessionStorage.setItem(this.logtoStorageKey, jsonItem);\n }\n\n get refreshToken() {\n return localStorage.getItem(buildRefreshTokenKey(this.logtoStorageKey));\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n const refreshTokenKey = buildRefreshTokenKey(this.logtoStorageKey);\n\n if (!refreshToken) {\n localStorage.removeItem(refreshTokenKey);\n\n return;\n }\n\n localStorage.setItem(refreshTokenKey, 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 const idTokenKey = buildIdTokenKey(this.logtoStorageKey);\n\n if (!idToken) {\n localStorage.removeItem(idTokenKey);\n\n return;\n }\n\n localStorage.setItem(idTokenKey, 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 = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n const state = 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 window.location.assign(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, requester } = this;\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.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 window.location.assign(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.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\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.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 }\n}\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
|
1
|
+
{"mappings":";AEKA,YAAY,EACV,aAAa,EACb,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,UAAU,EACV,SAAS,EACT,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,SAAS,GACV,MAAM,eAAe,CAAC;AAMvB,gCAAiC,SAAQ,UAAU;gBACrC,MAAM,EAAE,WAAW;CAWhC","sources":["packages/browser/src/src/storage.ts","packages/browser/src/src/utils/generators.ts","packages/browser/src/src/index.ts","packages/browser/src/index.ts"],"sourcesContent":[null,null,null,"import BaseClient, { createRequester, LogtoConfig } from '@logto/client';\n\nimport { BrowserStorage } from './storage';\nimport { generateCodeChallenge, generateCodeVerifier, generateState } from './utils/generators';\n\nexport type {\n IdTokenClaims,\n LogtoErrorCode,\n LogtoConfig,\n LogtoClientErrorCode,\n UserInfoResponse,\n} from '@logto/client';\n\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n LogtoClientError,\n ReservedScope,\n UserScope,\n} from '@logto/client';\n\nconst navigate = (url: string) => {\n window.location.assign(url);\n};\n\nexport default class LogtoClient extends BaseClient {\n constructor(config: LogtoConfig) {\n const requester = createRequester(fetch);\n super(config, {\n requester,\n navigate,\n storage: new BrowserStorage(config.appId),\n generateCodeChallenge,\n generateCodeVerifier,\n generateState,\n });\n }\n}\n"],"names":[],"version":3,"file":"index.d.ts.map"}
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
var $2FOI4$
|
|
2
|
-
var $2FOI4$
|
|
3
|
-
var $2FOI4$lodashonce = require("lodash.once");
|
|
4
|
-
var $2FOI4$superstruct = require("superstruct");
|
|
5
|
-
var $2FOI4$lodashget = require("lodash.get");
|
|
1
|
+
var $2FOI4$logtoclient = require("@logto/client");
|
|
2
|
+
var $2FOI4$jsbase64 = require("js-base64");
|
|
6
3
|
|
|
7
4
|
function $parcel$interopDefault(a) {
|
|
8
5
|
return a && a.__esModule ? a.default : a;
|
|
@@ -13,298 +10,81 @@ function $parcel$defineInteropFlag(a) {
|
|
|
13
10
|
function $parcel$export(e, n, v, s) {
|
|
14
11
|
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
15
12
|
}
|
|
16
|
-
function $parcel$exportWildcard(dest, source) {
|
|
17
|
-
Object.keys(source).forEach(function(key) {
|
|
18
|
-
if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Object.defineProperty(dest, key, {
|
|
23
|
-
enumerable: true,
|
|
24
|
-
get: function get() {
|
|
25
|
-
return source[key];
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return dest;
|
|
31
|
-
}
|
|
32
13
|
|
|
33
14
|
$parcel$defineInteropFlag(module.exports);
|
|
34
15
|
|
|
35
|
-
$parcel$export(module.exports, "LogtoSignInSessionItemSchema", () => $5a30d9203b683831$export$7b65a75f516b80e1);
|
|
36
16
|
$parcel$export(module.exports, "default", () => $5a30d9203b683831$export$2e2bcd8739ae039);
|
|
37
17
|
$parcel$export(module.exports, "LogtoError", () => $5a30d9203b683831$re_export$LogtoError);
|
|
38
18
|
$parcel$export(module.exports, "OidcError", () => $5a30d9203b683831$re_export$OidcError);
|
|
39
|
-
$parcel$export(module.exports, "Prompt", () => $
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
$
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.code = code;
|
|
68
|
-
this.data = data;
|
|
19
|
+
$parcel$export(module.exports, "Prompt", () => $5a30d9203b683831$re_export$Prompt);
|
|
20
|
+
$parcel$export(module.exports, "LogtoRequestError", () => $5a30d9203b683831$re_export$LogtoRequestError);
|
|
21
|
+
$parcel$export(module.exports, "LogtoClientError", () => $5a30d9203b683831$re_export$LogtoClientError);
|
|
22
|
+
$parcel$export(module.exports, "ReservedScope", () => $5a30d9203b683831$re_export$ReservedScope);
|
|
23
|
+
$parcel$export(module.exports, "UserScope", () => $5a30d9203b683831$re_export$UserScope);
|
|
24
|
+
|
|
25
|
+
const $5be5fc3fe8f0a1d3$export$9b5c2da5fe7b4b2b = `logto`;
|
|
26
|
+
class $5be5fc3fe8f0a1d3$export$2baa60fa09b100be {
|
|
27
|
+
constructor(appId){
|
|
28
|
+
this.storageKey = `${$5be5fc3fe8f0a1d3$export$9b5c2da5fe7b4b2b}:${appId}`;
|
|
29
|
+
}
|
|
30
|
+
async getItem(key) {
|
|
31
|
+
if (key === "signInSession") return sessionStorage.getItem(this.storageKey);
|
|
32
|
+
return localStorage.getItem(`${this.storageKey}:${key}`);
|
|
33
|
+
}
|
|
34
|
+
async setItem(key, value) {
|
|
35
|
+
if (key === "signInSession") {
|
|
36
|
+
sessionStorage.setItem(this.storageKey, value);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
localStorage.setItem(`${this.storageKey}:${key}`, value);
|
|
40
|
+
}
|
|
41
|
+
async removeItem(key) {
|
|
42
|
+
if (key === "signInSession") {
|
|
43
|
+
sessionStorage.removeItem(this.storageKey);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
69
47
|
}
|
|
70
48
|
}
|
|
71
49
|
|
|
72
50
|
|
|
73
51
|
|
|
74
|
-
const $944e6f79cbd4667b$var$logtoStorageItemKeyPrefix = `logto`;
|
|
75
|
-
const $944e6f79cbd4667b$export$bdf1d4f122e17e7b = (key)=>`${$944e6f79cbd4667b$var$logtoStorageItemKeyPrefix}:${key}`;
|
|
76
|
-
const $944e6f79cbd4667b$export$79da00f3c12fcb3c = (logtoKey)=>`${logtoKey}:refreshToken`;
|
|
77
|
-
const $944e6f79cbd4667b$export$cdb4d35801155147 = (logtoKey)=>`${logtoKey}:idToken`;
|
|
78
|
-
const $944e6f79cbd4667b$export$8f595bd2a47bcea6 = (resource = "", scopes = [])=>`${scopes.slice().sort().join(" ")}@${resource}`;
|
|
79
|
-
const $944e6f79cbd4667b$export$5d9c34f69c80822b = (endpoint)=>new URL((0, $2FOI4$logtojs.discoveryPath), endpoint).toString();
|
|
80
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @param length The length of the raw random data.
|
|
55
|
+
*/ const $baeb4f3d786047ef$var$generateRandomString = (length = 64)=>(0, $2FOI4$jsbase64.fromUint8Array)(crypto.getRandomValues(new Uint8Array(length)), true);
|
|
56
|
+
const $baeb4f3d786047ef$export$9ccd2716e53a229b = ()=>$baeb4f3d786047ef$var$generateRandomString();
|
|
57
|
+
const $baeb4f3d786047ef$export$cf1891f923f5943a = ()=>$baeb4f3d786047ef$var$generateRandomString();
|
|
58
|
+
const $baeb4f3d786047ef$export$414b01b1f867308a = async (codeVerifier)=>{
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
60
|
+
if (crypto.subtle === undefined) /**
|
|
61
|
+
* `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,
|
|
62
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle
|
|
63
|
+
* https://www.chromium.org/blink/webcrypto/#accessing-it
|
|
64
|
+
*/ throw new (0, $2FOI4$logtoclient.LogtoError)("crypto_subtle_unavailable");
|
|
65
|
+
const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);
|
|
66
|
+
const codeChallenge = new Uint8Array(await crypto.subtle.digest("SHA-256", encodedCodeVerifier));
|
|
67
|
+
return (0, $2FOI4$jsbase64.fromUint8Array)(codeChallenge, true);
|
|
68
|
+
};
|
|
81
69
|
|
|
82
70
|
|
|
83
71
|
|
|
84
|
-
const $5a30d9203b683831$
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
prompt: logtoConfig.prompt ?? (0, $2FOI4$logtojs.Prompt).Consent,
|
|
98
|
-
scopes: (0, $2FOI4$logtojs.withReservedScopes)(logtoConfig.scopes).split(" ")
|
|
99
|
-
};
|
|
100
|
-
this.logtoStorageKey = (0, $944e6f79cbd4667b$export$bdf1d4f122e17e7b)(logtoConfig.appId);
|
|
101
|
-
this.requester = requester;
|
|
102
|
-
this._idToken = localStorage.getItem((0, $944e6f79cbd4667b$export$cdb4d35801155147)(this.logtoStorageKey));
|
|
103
|
-
}
|
|
104
|
-
get isAuthenticated() {
|
|
105
|
-
return Boolean(this.idToken);
|
|
106
|
-
}
|
|
107
|
-
get signInSession() {
|
|
108
|
-
const jsonItem = sessionStorage.getItem(this.logtoStorageKey);
|
|
109
|
-
if (!jsonItem) return null;
|
|
110
|
-
try {
|
|
111
|
-
const item = JSON.parse(jsonItem);
|
|
112
|
-
(0, $2FOI4$superstruct.assert)(item, $5a30d9203b683831$export$7b65a75f516b80e1);
|
|
113
|
-
return item;
|
|
114
|
-
} catch (error) {
|
|
115
|
-
throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
set signInSession(logtoSignInSessionItem) {
|
|
119
|
-
if (!logtoSignInSessionItem) {
|
|
120
|
-
sessionStorage.removeItem(this.logtoStorageKey);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
124
|
-
sessionStorage.setItem(this.logtoStorageKey, jsonItem);
|
|
125
|
-
}
|
|
126
|
-
get refreshToken() {
|
|
127
|
-
return localStorage.getItem((0, $944e6f79cbd4667b$export$79da00f3c12fcb3c)(this.logtoStorageKey));
|
|
128
|
-
}
|
|
129
|
-
set refreshToken(refreshToken) {
|
|
130
|
-
const refreshTokenKey = (0, $944e6f79cbd4667b$export$79da00f3c12fcb3c)(this.logtoStorageKey);
|
|
131
|
-
if (!refreshToken) {
|
|
132
|
-
localStorage.removeItem(refreshTokenKey);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
localStorage.setItem(refreshTokenKey, refreshToken);
|
|
136
|
-
}
|
|
137
|
-
get idToken() {
|
|
138
|
-
return this._idToken;
|
|
139
|
-
}
|
|
140
|
-
set idToken(idToken) {
|
|
141
|
-
this._idToken = idToken;
|
|
142
|
-
const idTokenKey = (0, $944e6f79cbd4667b$export$cdb4d35801155147)(this.logtoStorageKey);
|
|
143
|
-
if (!idToken) {
|
|
144
|
-
localStorage.removeItem(idTokenKey);
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
localStorage.setItem(idTokenKey, idToken);
|
|
148
|
-
}
|
|
149
|
-
// eslint-disable-next-line complexity
|
|
150
|
-
async getAccessToken(resource) {
|
|
151
|
-
if (!this.idToken) throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("not_authenticated");
|
|
152
|
-
const accessTokenKey = (0, $944e6f79cbd4667b$export$8f595bd2a47bcea6)(resource);
|
|
153
|
-
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
154
|
-
if (accessToken && accessToken.expiresAt > Date.now() / 1000) return accessToken.token;
|
|
155
|
-
// Since the access token has expired, delete it from the map.
|
|
156
|
-
if (accessToken) this.accessTokenMap.delete(accessTokenKey);
|
|
157
|
-
/**
|
|
158
|
-
* Need to fetch a new access token using refresh token.
|
|
159
|
-
* Reuse the cached promise if exists.
|
|
160
|
-
*/ const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);
|
|
161
|
-
if (cachedPromise) return cachedPromise;
|
|
162
|
-
/**
|
|
163
|
-
* Create a new promise and cache in map to avoid race condition.
|
|
164
|
-
* Since we enable "refresh token rotation" by default,
|
|
165
|
-
* it will be problematic when calling multiple `getAccessToken()` closely.
|
|
166
|
-
*/ const promise = this.getAccessTokenByRefreshToken(resource);
|
|
167
|
-
this.getAccessTokenPromiseMap.set(accessTokenKey, promise);
|
|
168
|
-
const token = await promise;
|
|
169
|
-
this.getAccessTokenPromiseMap.delete(accessTokenKey);
|
|
170
|
-
return token;
|
|
171
|
-
}
|
|
172
|
-
getIdTokenClaims() {
|
|
173
|
-
if (!this.idToken) throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("not_authenticated");
|
|
174
|
-
return (0, $2FOI4$logtojs.decodeIdToken)(this.idToken);
|
|
175
|
-
}
|
|
176
|
-
async signIn(redirectUri) {
|
|
177
|
-
const { appId: clientId , prompt: prompt , resources: resources , scopes: scopes } = this.logtoConfig;
|
|
178
|
-
const { authorizationEndpoint: authorizationEndpoint } = await this.getOidcConfig();
|
|
179
|
-
const codeVerifier = (0, $2FOI4$logtojs.generateCodeVerifier)();
|
|
180
|
-
const codeChallenge = await (0, $2FOI4$logtojs.generateCodeChallenge)(codeVerifier);
|
|
181
|
-
const state = (0, $2FOI4$logtojs.generateState)();
|
|
182
|
-
const signInUri = (0, $2FOI4$logtojs.generateSignInUri)({
|
|
183
|
-
authorizationEndpoint: authorizationEndpoint,
|
|
184
|
-
clientId: clientId,
|
|
185
|
-
redirectUri: redirectUri,
|
|
186
|
-
codeChallenge: codeChallenge,
|
|
187
|
-
state: state,
|
|
188
|
-
scopes: scopes,
|
|
189
|
-
resources: resources,
|
|
190
|
-
prompt: prompt
|
|
191
|
-
});
|
|
192
|
-
this.signInSession = {
|
|
193
|
-
redirectUri: redirectUri,
|
|
194
|
-
codeVerifier: codeVerifier,
|
|
195
|
-
state: state
|
|
196
|
-
};
|
|
197
|
-
this.refreshToken = null;
|
|
198
|
-
this.idToken = null;
|
|
199
|
-
window.location.assign(signInUri);
|
|
200
|
-
}
|
|
201
|
-
isSignInRedirected(url) {
|
|
202
|
-
const { signInSession: signInSession } = this;
|
|
203
|
-
if (!signInSession) return false;
|
|
204
|
-
const { redirectUri: redirectUri } = signInSession;
|
|
205
|
-
const { origin: origin , pathname: pathname } = new URL(url);
|
|
206
|
-
return `${origin}${pathname}` === redirectUri;
|
|
207
|
-
}
|
|
208
|
-
async handleSignInCallback(callbackUri) {
|
|
209
|
-
const { signInSession: signInSession , logtoConfig: logtoConfig , requester: requester } = this;
|
|
210
|
-
if (!signInSession) throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("sign_in_session.not_found");
|
|
211
|
-
const { redirectUri: redirectUri , state: state , codeVerifier: codeVerifier } = signInSession;
|
|
212
|
-
const code = (0, $2FOI4$logtojs.verifyAndParseCodeFromCallbackUri)(callbackUri, redirectUri, state);
|
|
213
|
-
const { appId: clientId } = logtoConfig;
|
|
214
|
-
const { tokenEndpoint: tokenEndpoint } = await this.getOidcConfig();
|
|
215
|
-
const codeTokenResponse = await (0, $2FOI4$logtojs.fetchTokenByAuthorizationCode)({
|
|
216
|
-
clientId: clientId,
|
|
217
|
-
tokenEndpoint: tokenEndpoint,
|
|
218
|
-
redirectUri: redirectUri,
|
|
219
|
-
codeVerifier: codeVerifier,
|
|
220
|
-
code: code
|
|
221
|
-
}, requester);
|
|
222
|
-
await this.verifyIdToken(codeTokenResponse.idToken);
|
|
223
|
-
this.saveCodeToken(codeTokenResponse);
|
|
224
|
-
this.signInSession = null;
|
|
225
|
-
}
|
|
226
|
-
async signOut(postLogoutRedirectUri) {
|
|
227
|
-
if (!this.idToken) throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("not_authenticated");
|
|
228
|
-
const { appId: clientId } = this.logtoConfig;
|
|
229
|
-
const { endSessionEndpoint: endSessionEndpoint , revocationEndpoint: revocationEndpoint } = await this.getOidcConfig();
|
|
230
|
-
if (this.refreshToken) try {
|
|
231
|
-
await (0, $2FOI4$logtojs.revoke)(revocationEndpoint, clientId, this.refreshToken, this.requester);
|
|
232
|
-
} catch {
|
|
233
|
-
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
234
|
-
}
|
|
235
|
-
const url = (0, $2FOI4$logtojs.generateSignOutUri)({
|
|
236
|
-
endSessionEndpoint: endSessionEndpoint,
|
|
237
|
-
postLogoutRedirectUri: postLogoutRedirectUri,
|
|
238
|
-
idToken: this.idToken
|
|
239
|
-
});
|
|
240
|
-
this.accessTokenMap.clear();
|
|
241
|
-
this.refreshToken = null;
|
|
242
|
-
this.idToken = null;
|
|
243
|
-
window.location.assign(url);
|
|
244
|
-
}
|
|
245
|
-
async getAccessTokenByRefreshToken(resource) {
|
|
246
|
-
if (!this.refreshToken) throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("not_authenticated");
|
|
247
|
-
try {
|
|
248
|
-
const accessTokenKey = (0, $944e6f79cbd4667b$export$8f595bd2a47bcea6)(resource);
|
|
249
|
-
const { appId: clientId } = this.logtoConfig;
|
|
250
|
-
const { tokenEndpoint: tokenEndpoint } = await this.getOidcConfig();
|
|
251
|
-
const { accessToken: accessToken , refreshToken: refreshToken , idToken: idToken , scope: scope , expiresIn: expiresIn } = await (0, $2FOI4$logtojs.fetchTokenByRefreshToken)({
|
|
252
|
-
clientId: clientId,
|
|
253
|
-
tokenEndpoint: tokenEndpoint,
|
|
254
|
-
refreshToken: this.refreshToken,
|
|
255
|
-
resource: resource,
|
|
256
|
-
scopes: resource ? [
|
|
257
|
-
"offline_access"
|
|
258
|
-
] : undefined
|
|
259
|
-
}, this.requester);
|
|
260
|
-
this.accessTokenMap.set(accessTokenKey, {
|
|
261
|
-
token: accessToken,
|
|
262
|
-
scope: scope,
|
|
263
|
-
expiresAt: Math.round(Date.now() / 1000) + expiresIn
|
|
264
|
-
});
|
|
265
|
-
this.refreshToken = refreshToken;
|
|
266
|
-
if (idToken) {
|
|
267
|
-
await this.verifyIdToken(idToken);
|
|
268
|
-
this.idToken = idToken;
|
|
269
|
-
}
|
|
270
|
-
return accessToken;
|
|
271
|
-
} catch (error) {
|
|
272
|
-
throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("get_access_token_by_refresh_token_failed", error);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
async _getOidcConfig() {
|
|
276
|
-
const { endpoint: endpoint } = this.logtoConfig;
|
|
277
|
-
const discoveryEndpoint = (0, $944e6f79cbd4667b$export$5d9c34f69c80822b)(endpoint);
|
|
278
|
-
return (0, $2FOI4$logtojs.fetchOidcConfig)(discoveryEndpoint, this.requester);
|
|
279
|
-
}
|
|
280
|
-
async _getJwtVerifyGetKey() {
|
|
281
|
-
const { jwksUri: jwksUri } = await this.getOidcConfig();
|
|
282
|
-
return (0, $2FOI4$jose.createRemoteJWKSet)(new URL(jwksUri));
|
|
283
|
-
}
|
|
284
|
-
async verifyIdToken(idToken) {
|
|
285
|
-
const { appId: appId } = this.logtoConfig;
|
|
286
|
-
const { issuer: issuer } = await this.getOidcConfig();
|
|
287
|
-
const jwtVerifyGetKey = await this.getJwtVerifyGetKey();
|
|
288
|
-
try {
|
|
289
|
-
await (0, $2FOI4$logtojs.verifyIdToken)(idToken, appId, issuer, jwtVerifyGetKey);
|
|
290
|
-
} catch (error) {
|
|
291
|
-
throw new (0, $91774f8557d77d78$export$877962ca249b8fc8)("invalid_id_token", error);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
295
|
-
this.refreshToken = refreshToken ?? null;
|
|
296
|
-
this.idToken = idToken;
|
|
297
|
-
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
298
|
-
const accessTokenKey = (0, $944e6f79cbd4667b$export$8f595bd2a47bcea6)();
|
|
299
|
-
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
300
|
-
this.accessTokenMap.set(accessTokenKey, {
|
|
301
|
-
token: accessToken,
|
|
302
|
-
scope: scope,
|
|
303
|
-
expiresAt: expiresAt
|
|
72
|
+
const $5a30d9203b683831$var$navigate = (url)=>{
|
|
73
|
+
window.location.assign(url);
|
|
74
|
+
};
|
|
75
|
+
class $5a30d9203b683831$export$2e2bcd8739ae039 extends (0, ($parcel$interopDefault($2FOI4$logtoclient))) {
|
|
76
|
+
constructor(config){
|
|
77
|
+
const requester = (0, $2FOI4$logtoclient.createRequester)(fetch);
|
|
78
|
+
super(config, {
|
|
79
|
+
requester: requester,
|
|
80
|
+
navigate: $5a30d9203b683831$var$navigate,
|
|
81
|
+
storage: new (0, $5be5fc3fe8f0a1d3$export$2baa60fa09b100be)(config.appId),
|
|
82
|
+
generateCodeChallenge: $baeb4f3d786047ef$export$414b01b1f867308a,
|
|
83
|
+
generateCodeVerifier: $baeb4f3d786047ef$export$cf1891f923f5943a,
|
|
84
|
+
generateState: $baeb4f3d786047ef$export$9ccd2716e53a229b
|
|
304
85
|
});
|
|
305
86
|
}
|
|
306
87
|
}
|
|
307
|
-
$parcel$exportWildcard(module.exports, $91774f8557d77d78$exports);
|
|
308
88
|
|
|
309
89
|
|
|
310
90
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;ACAA;AAGA,MAAM,2CAAqB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,eAAe,EAAE;QACf,OAAO,EAAE,0BAA0B;QACnC,SAAS,EAAE,4BAA4B;KACxC;IACD,iBAAiB,EAAE,oBAAoB;IACvC,wCAAwC,EAAE,8CAA8C;IACxF,gBAAgB,EAAE,mBAAmB;CACtC,CAAC,AAAC;AAIH,MAAM,2CAAqB,GAAG,CAAC,SAA+B,GAAa;IACzE,8BAA8B;IAC9B,mEAAmE;IACnE,MAAM,OAAO,GAAG,CAAA,GAAA,0CAAG,CAAA,CAAC,2CAAqB,EAAE,SAAS,CAAC,AAAC;IAEtD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAC7B,OAAO,OAAO,CAAC;IAGjB,OAAO,SAAS,CAAC;CAClB,AAAC;AAEK,MAAM,yCAAgB,SAAS,KAAK;IAIzC,YAAY,IAA0B,EAAE,IAAc,CAAE;QACtD,KAAK,CAAC,2CAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;KAClB;CACF;;;ACpCD;AAEA,MAAM,+CAAyB,GAAG,CAAC,KAAK,CAAC,AAAC;AACnC,MAAM,yCAAa,GAAG,CAAC,GAAW,GAAa,CAAC,EAAE,+CAAyB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,AAAC;AACrF,MAAM,yCAAoB,GAAG,CAAC,QAAgB,GAAK,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,AAAC;AAC9E,MAAM,yCAAe,GAAG,CAAC,QAAgB,GAAK,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,AAAC;AAEpE,MAAM,yCAAmB,GAAG,CAAC,QAAQ,GAAG,EAAE,EAAE,MAAgB,GAAG,EAAE,GACtE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,AAAC;AAE5C,MAAM,yCAAoB,GAAG,CAAC,QAAgB,GACnD,IAAI,GAAG,CAAC,CAAA,GAAA,4BAAa,CAAA,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,AAAC;;;;;AF0CvC,MAAM,yCAA4B,GAAG,CAAA,GAAA,uBAAI,CAAA,CAAC;IAC/C,WAAW,EAAE,CAAA,GAAA,yBAAM,CAAA,EAAE;IACrB,YAAY,EAAE,CAAA,GAAA,yBAAM,CAAA,EAAE;IACtB,KAAK,EAAE,CAAA,GAAA,yBAAM,CAAA,EAAE;CAChB,CAAC,AAAC;AAIY;IAEb,AAAmB,aAAa,GAAG,CAAA,GAAA,2CAAI,CAAA,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7D,AAAmB,kBAAkB,GAAG,CAAA,GAAA,2CAAI,CAAA,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAKvE,AAAmB,cAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEnE,AAAiB,wBAAwB,GAAG,IAAI,GAAG,EAA2B,CAAC;IAG/E,YAAY,WAAwB,EAAE,SAAS,GAAG,CAAA,GAAA,8BAAe,CAAA,EAAE,CAAE;QACnE,IAAI,CAAC,WAAW,GAAG;YACjB,GAAG,WAAW;YACd,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,CAAA,GAAA,qBAAM,CAAA,CAAC,OAAO;YAC5C,MAAM,EAAE,CAAA,GAAA,iCAAkB,CAAA,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;SAC1D,CAAC;QACF,IAAI,CAAC,eAAe,GAAG,CAAA,GAAA,yCAAa,CAAA,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA,GAAA,yCAAe,CAAA,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;KAC7E;IAED,IAAW,eAAe,GAAG;QAC3B,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC9B;IAED,IAAc,aAAa,GAAqC;QAC9D,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,AAAC;QAE9D,IAAI,CAAC,QAAQ,EACX,OAAO,IAAI,CAAC;QAGd,IAAI;YACF,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,AAAC;YAC3C,CAAA,GAAA,yBAAM,CAAA,CAAC,IAAI,EAAE,yCAA4B,CAAC,CAAC;YAE3C,OAAO,IAAI,CAAC;SACb,CAAC,OAAO,KAAK,EAAW;YACvB,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;SAC9D;KACF;IAED,IAAc,aAAa,CAAC,sBAAwD,EAAE;QACpF,IAAI,CAAC,sBAAsB,EAAE;YAC3B,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAEhD,OAAO;SACR;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,AAAC;QACxD,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;KACxD;IAED,IAAI,YAAY,GAAG;QACjB,OAAO,YAAY,CAAC,OAAO,CAAC,CAAA,GAAA,yCAAoB,CAAA,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;KACzE;IAED,IAAY,YAAY,CAAC,YAA8B,EAAE;QACvD,MAAM,eAAe,GAAG,CAAA,GAAA,yCAAoB,CAAA,CAAC,IAAI,CAAC,eAAe,CAAC,AAAC;QAEnE,IAAI,CAAC,YAAY,EAAE;YACjB,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;YAEzC,OAAO;SACR;QAED,YAAY,CAAC,OAAO,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;KACrD;IAED,IAAI,OAAO,GAAG;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;KACtB;IAED,IAAY,OAAO,CAAC,OAAyB,EAAE;QAC7C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAExB,MAAM,UAAU,GAAG,CAAA,GAAA,yCAAe,CAAA,CAAC,IAAI,CAAC,eAAe,CAAC,AAAC;QAEzD,IAAI,CAAC,OAAO,EAAE;YACZ,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YAEpC,OAAO;SACR;QAED,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;KAC3C;IAED,sCAAsC;IACtC,MAAa,cAAc,CAAC,QAAiB,EAAmB;QAC9D,IAAI,CAAC,IAAI,CAAC,OAAO,EACf,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,mBAAmB,CAAC,CAAC;QAGlD,MAAM,cAAc,GAAG,CAAA,GAAA,yCAAmB,CAAA,CAAC,QAAQ,CAAC,AAAC;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,AAAC;QAE5D,IAAI,WAAW,IAAI,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAC1D,OAAO,WAAW,CAAC,KAAK,CAAC;QAG3B,8DAA8D;QAC9D,IAAI,WAAW,EACb,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAG7C;;;OAGG,CACH,MAAM,aAAa,GAAG,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,cAAc,CAAC,AAAC;QAExE,IAAI,aAAa,EACf,OAAO,aAAa,CAAC;QAGvB;;;;OAIG,CACH,MAAM,OAAO,GAAG,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,AAAC;QAC5D,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAE3D,MAAM,KAAK,GAAG,MAAM,OAAO,AAAC;QAC5B,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAErD,OAAO,KAAK,CAAC;KACd;IAED,AAAO,gBAAgB,GAAkB;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,EACf,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,mBAAmB,CAAC,CAAC;QAGlD,OAAO,CAAA,GAAA,4BAAa,CAAA,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KACpC;IAED,MAAa,MAAM,CAAC,WAAmB,EAAE;QACvC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAA,UAAE,MAAM,CAAA,aAAE,SAAS,CAAA,UAAE,MAAM,CAAA,EAAE,GAAG,IAAI,CAAC,WAAW,AAAC;QACxE,MAAM,yBAAE,qBAAqB,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;QAC7D,MAAM,YAAY,GAAG,CAAA,GAAA,mCAAoB,CAAA,EAAE,AAAC;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAA,GAAA,oCAAqB,CAAA,CAAC,YAAY,CAAC,AAAC;QAChE,MAAM,KAAK,GAAG,CAAA,GAAA,4BAAa,CAAA,EAAE,AAAC;QAE9B,MAAM,SAAS,GAAG,CAAA,GAAA,gCAAiB,CAAA,CAAC;mCAClC,qBAAqB;sBACrB,QAAQ;yBACR,WAAW;2BACX,aAAa;mBACb,KAAK;oBACL,MAAM;uBACN,SAAS;oBACT,MAAM;SACP,CAAC,AAAC;QAEH,IAAI,CAAC,aAAa,GAAG;yBAAE,WAAW;0BAAE,YAAY;mBAAE,KAAK;SAAE,CAAC;QAC1D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;KACnC;IAED,AAAO,kBAAkB,CAAC,GAAW,EAAW;QAC9C,MAAM,iBAAE,aAAa,CAAA,EAAE,GAAG,IAAI,AAAC;QAE/B,IAAI,CAAC,aAAa,EAChB,OAAO,KAAK,CAAC;QAEf,MAAM,eAAE,WAAW,CAAA,EAAE,GAAG,aAAa,AAAC;QACtC,MAAM,UAAE,MAAM,CAAA,YAAE,QAAQ,CAAA,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,AAAC;QAE1C,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,WAAW,CAAC;KAC/C;IAED,MAAa,oBAAoB,CAAC,WAAmB,EAAE;QACrD,MAAM,iBAAE,aAAa,CAAA,eAAE,WAAW,CAAA,aAAE,SAAS,CAAA,EAAE,GAAG,IAAI,AAAC;QAEvD,IAAI,CAAC,aAAa,EAChB,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,2BAA2B,CAAC,CAAC;QAG1D,MAAM,eAAE,WAAW,CAAA,SAAE,KAAK,CAAA,gBAAE,YAAY,CAAA,EAAE,GAAG,aAAa,AAAC;QAC3D,MAAM,IAAI,GAAG,CAAA,GAAA,gDAAiC,CAAA,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,AAAC;QAEhF,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAA,EAAE,GAAG,WAAW,AAAC;QACxC,MAAM,iBAAE,aAAa,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;QACrD,MAAM,iBAAiB,GAAG,MAAM,CAAA,GAAA,4CAA6B,CAAA,CAC3D;sBACE,QAAQ;2BACR,aAAa;yBACb,WAAW;0BACX,YAAY;kBACZ,IAAI;SACL,EACD,SAAS,CACV,AAAC;QAEF,MAAM,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAEpD,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACtC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;KAC3B;IAED,MAAa,OAAO,CAAC,qBAA8B,EAAE;QACnD,IAAI,CAAC,IAAI,CAAC,OAAO,EACf,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,mBAAmB,CAAC,CAAC;QAGlD,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAA,EAAE,GAAG,IAAI,CAAC,WAAW,AAAC;QAC7C,MAAM,sBAAE,kBAAkB,CAAA,sBAAE,kBAAkB,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;QAE9E,IAAI,IAAI,CAAC,YAAY,EACnB,IAAI;YACF,MAAM,CAAA,GAAA,qBAAM,CAAA,CAAC,kBAAkB,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;SAC/E,CAAC,OAAM;QACN,yGAAyG;SAC1G;QAGH,MAAM,GAAG,GAAG,CAAA,GAAA,iCAAkB,CAAA,CAAC;gCAC7B,kBAAkB;mCAClB,qBAAqB;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,AAAC;QAEH,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAC7B;IAED,MAAc,4BAA4B,CAAC,QAAiB,EAAmB;QAC7E,IAAI,CAAC,IAAI,CAAC,YAAY,EACpB,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,mBAAmB,CAAC,CAAC;QAGlD,IAAI;YACF,MAAM,cAAc,GAAG,CAAA,GAAA,yCAAmB,CAAA,CAAC,QAAQ,CAAC,AAAC;YACrD,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAA,EAAE,GAAG,IAAI,CAAC,WAAW,AAAC;YAC7C,MAAM,iBAAE,aAAa,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;YACrD,MAAM,eAAE,WAAW,CAAA,gBAAE,YAAY,CAAA,WAAE,OAAO,CAAA,SAAE,KAAK,CAAA,aAAE,SAAS,CAAA,EAAE,GAC5D,MAAM,CAAA,GAAA,uCAAwB,CAAA,CAC5B;0BACE,QAAQ;+BACR,aAAa;gBACb,YAAY,EAAE,IAAI,CAAC,YAAY;0BAC/B,QAAQ;gBACR,MAAM,EAAE,QAAQ,GAAG;oBAAC,gBAAgB;iBAAC,GAAG,SAAS;aAClD,EACD,IAAI,CAAC,SAAS,CACf,AAAC;YAEJ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,EAAE;gBACtC,KAAK,EAAE,WAAW;uBAClB,KAAK;gBACL,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS;aACrD,CAAC,CAAC;YAEH,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;YAEjC,IAAI,OAAO,EAAE;gBACX,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;aACxB;YAED,OAAO,WAAW,CAAC;SACpB,CAAC,OAAO,KAAK,EAAW;YACvB,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;SAC/E;KACF;IAED,MAAc,cAAc,GAAG;QAC7B,MAAM,YAAE,QAAQ,CAAA,EAAE,GAAG,IAAI,CAAC,WAAW,AAAC;QACtC,MAAM,iBAAiB,GAAG,CAAA,GAAA,yCAAoB,CAAA,CAAC,QAAQ,CAAC,AAAC;QAEzD,OAAO,CAAA,GAAA,8BAAe,CAAA,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;KAC3D;IAED,MAAc,mBAAmB,GAAG;QAClC,MAAM,WAAE,OAAO,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;QAE/C,OAAO,CAAA,GAAA,8BAAkB,CAAA,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;KAC7C;IAED,MAAc,aAAa,CAAC,OAAe,EAAE;QAC3C,MAAM,SAAE,KAAK,CAAA,EAAE,GAAG,IAAI,CAAC,WAAW,AAAC;QACnC,MAAM,UAAE,MAAM,CAAA,EAAE,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,AAAC;QAC9C,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,AAAC;QAExD,IAAI;YACF,MAAM,CAAA,GAAA,4BAAa,CAAA,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;SAC9D,CAAC,OAAO,KAAK,EAAW;YACvB,MAAM,IAAI,CAAA,GAAA,yCAAgB,CAAA,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;SACvD;KACF;IAED,AAAQ,aAAa,CAAC,gBACpB,YAAY,CAAA,WACZ,OAAO,CAAA,SACP,KAAK,CAAA,eACL,WAAW,CAAA,aACX,SAAS,CAAA,EACS,EAAE;QACpB,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,IAAI,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,8EAA8E;QAC9E,MAAM,cAAc,GAAG,CAAA,GAAA,yCAAmB,CAAA,EAAE,AAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,AAAC;QAChD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,EAAE;YAAE,KAAK,EAAE,WAAW;mBAAE,KAAK;uBAAE,SAAS;SAAE,CAAC,CAAC;KACnF;CACF","sources":["packages/browser/src/index.ts","packages/browser/src/errors.ts","packages/browser/src/utils/index.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n createRequester,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateCodeChallenge,\n generateCodeVerifier,\n generateSignInUri,\n generateSignOutUri,\n generateState,\n IdTokenClaims,\n Prompt,\n Requester,\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, Infer, string, type } from 'superstruct';\n\nimport { LogtoClientError } from './errors';\nimport {\n buildAccessTokenKey,\n buildIdTokenKey,\n buildLogtoKey,\n buildRefreshTokenKey,\n getDiscoveryEndpoint,\n} from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt } from '@logto/js';\nexport * from './errors';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n usingPersistStorage?: boolean;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number; // Unix Timestamp in seconds\n};\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\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 logtoStorageKey: string;\n protected readonly requester: Requester;\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, requester = createRequester()) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.logtoStorageKey = buildLogtoKey(logtoConfig.appId);\n this.requester = requester;\n this._idToken = localStorage.getItem(buildIdTokenKey(this.logtoStorageKey));\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = sessionStorage.getItem(this.logtoStorageKey);\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 sessionStorage.removeItem(this.logtoStorageKey);\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n sessionStorage.setItem(this.logtoStorageKey, jsonItem);\n }\n\n get refreshToken() {\n return localStorage.getItem(buildRefreshTokenKey(this.logtoStorageKey));\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n const refreshTokenKey = buildRefreshTokenKey(this.logtoStorageKey);\n\n if (!refreshToken) {\n localStorage.removeItem(refreshTokenKey);\n\n return;\n }\n\n localStorage.setItem(refreshTokenKey, 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 const idTokenKey = buildIdTokenKey(this.logtoStorageKey);\n\n if (!idToken) {\n localStorage.removeItem(idTokenKey);\n\n return;\n }\n\n localStorage.setItem(idTokenKey, 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 = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n const state = 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 window.location.assign(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, requester } = this;\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.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 window.location.assign(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.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\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.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 }\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 // TODO: linear issue LOG-1419\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 { discoveryPath } from '@logto/js';\n\nconst logtoStorageItemKeyPrefix = `logto`;\nexport const buildLogtoKey = (key: string): string => `${logtoStorageItemKeyPrefix}:${key}`;\nexport const buildRefreshTokenKey = (logtoKey: string) => `${logtoKey}:refreshToken`;\nexport const buildIdTokenKey = (logtoKey: string) => `${logtoKey}:idToken`;\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"],"names":[],"version":3,"file":"index.js.map"}
|
|
1
|
+
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;ACGO,MAAM,yCAAyB,GAAG,CAAC,KAAK,CAAC,AAAC;AAE1C,MAAM,yCAAc;IAGzB,YAAY,KAAa,CAAE;QACzB,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,yCAAyB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;KAC3D;IAED,MAAM,OAAO,CAAC,GAAe,EAA6B;QACxD,IAAI,GAAG,KAAK,eAAe,EACzB,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAGjD,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;KAC1D;IAED,MAAM,OAAO,CAAC,GAAe,EAAE,KAAa,EAAiB;QAC3D,IAAI,GAAG,KAAK,eAAe,EAAE;YAC3B,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAE/C,OAAO;SACR;QACD,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;KAC1D;IAED,MAAM,UAAU,CAAC,GAAe,EAAiB;QAC/C,IAAI,GAAG,KAAK,eAAe,EAAE;YAC3B,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAE3C,OAAO;SACR;QACD,YAAY,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;KACtD;CACF;;;ACnCD;;AAGA;;GAEG,CACH,MAAM,0CAAoB,GAAG,CAAC,MAAM,GAAG,EAAE,GACvC,CAAA,GAAA,8BAAc,CAAA,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,AAAC;AAKhE,MAAM,yCAAa,GAAG,IAAM,0CAAoB,EAAE,AAAC;AAOnD,MAAM,yCAAoB,GAAG,IAAM,0CAAoB,EAAE,AAAC;AAQ1D,MAAM,yCAAqB,GAAG,OAAO,YAAoB,GAAsB;IACpF,uEAAuE;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAC7B;;;;OAIG,CACH,MAAM,IAAI,CAAA,GAAA,6BAAU,CAAA,CAAC,2BAA2B,CAAC,CAAC;IAGpD,MAAM,mBAAmB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,AAAC;IACnE,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC,AAAC;IAEjG,OAAO,CAAA,GAAA,8BAAc,CAAA,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;CAC5C,AAAC;;;;AFrBF,MAAM,8BAAQ,GAAG,CAAC,GAAW,GAAK;IAChC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;CAC7B,AAAC;AAEa,uDAA0B,CAAA,GAAA,4CAAU,CAAA;IACjD,YAAY,MAAmB,CAAE;QAC/B,MAAM,SAAS,GAAG,CAAA,GAAA,kCAAe,CAAA,CAAC,KAAK,CAAC,AAAC;QACzC,KAAK,CAAC,MAAM,EAAE;uBACZ,SAAS;sBACT,8BAAQ;YACR,OAAO,EAAE,IAAI,CAAA,GAAA,yCAAc,CAAA,CAAC,MAAM,CAAC,KAAK,CAAC;mCACzC,yCAAqB;kCACrB,yCAAoB;2BACpB,yCAAa;SACd,CAAC,CAAC;KACJ;CACF","sources":["packages/browser/src/index.ts","packages/browser/src/storage.ts","packages/browser/src/utils/generators.ts"],"sourcesContent":["import BaseClient, { createRequester, LogtoConfig } from '@logto/client';\n\nimport { BrowserStorage } from './storage';\nimport { generateCodeChallenge, generateCodeVerifier, generateState } from './utils/generators';\n\nexport type {\n IdTokenClaims,\n LogtoErrorCode,\n LogtoConfig,\n LogtoClientErrorCode,\n UserInfoResponse,\n} from '@logto/client';\n\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n LogtoClientError,\n ReservedScope,\n UserScope,\n} from '@logto/client';\n\nconst navigate = (url: string) => {\n window.location.assign(url);\n};\n\nexport default class LogtoClient extends BaseClient {\n constructor(config: LogtoConfig) {\n const requester = createRequester(fetch);\n super(config, {\n requester,\n navigate,\n storage: new BrowserStorage(config.appId),\n generateCodeChallenge,\n generateCodeVerifier,\n generateState,\n });\n }\n}\n","import { Storage, StorageKey } from '@logto/client';\nimport { Nullable } from '@silverhand/essentials';\n\nexport const logtoStorageItemKeyPrefix = `logto`;\n\nexport class BrowserStorage implements Storage {\n private readonly storageKey: string;\n\n constructor(appId: string) {\n this.storageKey = `${logtoStorageItemKeyPrefix}:${appId}`;\n }\n\n async getItem(key: StorageKey): Promise<Nullable<string>> {\n if (key === 'signInSession') {\n return sessionStorage.getItem(this.storageKey);\n }\n\n return localStorage.getItem(`${this.storageKey}:${key}`);\n }\n\n async setItem(key: StorageKey, value: string): Promise<void> {\n if (key === 'signInSession') {\n sessionStorage.setItem(this.storageKey, value);\n\n return;\n }\n localStorage.setItem(`${this.storageKey}:${key}`, value);\n }\n\n async removeItem(key: StorageKey): Promise<void> {\n if (key === 'signInSession') {\n sessionStorage.removeItem(this.storageKey);\n\n return;\n }\n localStorage.removeItem(`${this.storageKey}:${key}`);\n }\n}\n","/** @link [Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) */\n\nimport { LogtoError } from '@logto/client';\nimport { fromUint8Array } from 'js-base64';\n\n/**\n * @param length The length of the raw random data.\n */\nconst generateRandomString = (length = 64) =>\n fromUint8Array(crypto.getRandomValues(new Uint8Array(length)), true);\n\n/**\n * Generates random string for state and encodes them in url safe base64\n */\nexport const generateState = () => generateRandomString();\n\n/**\n * Generates code verifier\n *\n * @link [Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1)\n */\nexport const generateCodeVerifier = () => generateRandomString();\n\n/**\n * Calculates the S256 PKCE code challenge for an arbitrary code verifier and encodes it in url safe base64\n *\n * @param {String} codeVerifier Code verifier to calculate the S256 code challenge for\n * @link [Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2)\n */\nexport const generateCodeChallenge = async (codeVerifier: string): Promise<string> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (crypto.subtle === undefined) {\n /**\n * `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,\n * https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle\n * https://www.chromium.org/blink/webcrypto/#accessing-it\n */\n throw new LogtoError('crypto_subtle_unavailable');\n }\n\n const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);\n const codeChallenge = new Uint8Array(await crypto.subtle.digest('SHA-256', encodedCodeVerifier));\n\n return fromUint8Array(codeChallenge, true);\n};\n"],"names":[],"version":3,"file":"index.js.map"}
|
package/lib/module.js
CHANGED
|
@@ -1,280 +1,71 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import $ElS14$lodashonce from "lodash.once";
|
|
4
|
-
import {type as $ElS14$type, string as $ElS14$string, assert as $ElS14$assert} from "superstruct";
|
|
5
|
-
import $ElS14$lodashget from "lodash.get";
|
|
1
|
+
import $ElS14$logtoclient, {createRequester as $ElS14$createRequester, LogtoError as $90df2ab0e44b5eba$re_export$LogtoError, OidcError as $90df2ab0e44b5eba$re_export$OidcError, Prompt as $90df2ab0e44b5eba$re_export$Prompt, LogtoRequestError as $90df2ab0e44b5eba$re_export$LogtoRequestError, LogtoClientError as $90df2ab0e44b5eba$re_export$LogtoClientError, ReservedScope as $90df2ab0e44b5eba$re_export$ReservedScope, UserScope as $90df2ab0e44b5eba$re_export$UserScope} from "@logto/client";
|
|
2
|
+
import {fromUint8Array as $ElS14$fromUint8Array} from "js-base64";
|
|
6
3
|
|
|
7
|
-
function $parcel$export(e, n, v, s) {
|
|
8
|
-
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var $092943c955830b14$exports = {};
|
|
15
|
-
|
|
16
|
-
$parcel$export($092943c955830b14$exports, "LogtoClientError", () => $092943c955830b14$export$877962ca249b8fc8);
|
|
17
4
|
|
|
18
|
-
const $
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
5
|
+
const $283691d41cf73b69$export$9b5c2da5fe7b4b2b = `logto`;
|
|
6
|
+
class $283691d41cf73b69$export$2baa60fa09b100be {
|
|
7
|
+
constructor(appId){
|
|
8
|
+
this.storageKey = `${$283691d41cf73b69$export$9b5c2da5fe7b4b2b}:${appId}`;
|
|
9
|
+
}
|
|
10
|
+
async getItem(key) {
|
|
11
|
+
if (key === "signInSession") return sessionStorage.getItem(this.storageKey);
|
|
12
|
+
return localStorage.getItem(`${this.storageKey}:${key}`);
|
|
13
|
+
}
|
|
14
|
+
async setItem(key, value) {
|
|
15
|
+
if (key === "signInSession") {
|
|
16
|
+
sessionStorage.setItem(this.storageKey, value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
localStorage.setItem(`${this.storageKey}:${key}`, value);
|
|
20
|
+
}
|
|
21
|
+
async removeItem(key) {
|
|
22
|
+
if (key === "signInSession") {
|
|
23
|
+
sessionStorage.removeItem(this.storageKey);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
localStorage.removeItem(`${this.storageKey}:${key}`);
|
|
39
27
|
}
|
|
40
28
|
}
|
|
41
29
|
|
|
42
30
|
|
|
43
31
|
|
|
44
|
-
const $2f0dba05fbbfeb85$var$logtoStorageItemKeyPrefix = `logto`;
|
|
45
|
-
const $2f0dba05fbbfeb85$export$bdf1d4f122e17e7b = (key)=>`${$2f0dba05fbbfeb85$var$logtoStorageItemKeyPrefix}:${key}`;
|
|
46
|
-
const $2f0dba05fbbfeb85$export$79da00f3c12fcb3c = (logtoKey)=>`${logtoKey}:refreshToken`;
|
|
47
|
-
const $2f0dba05fbbfeb85$export$cdb4d35801155147 = (logtoKey)=>`${logtoKey}:idToken`;
|
|
48
|
-
const $2f0dba05fbbfeb85$export$8f595bd2a47bcea6 = (resource = "", scopes = [])=>`${scopes.slice().sort().join(" ")}@${resource}`;
|
|
49
|
-
const $2f0dba05fbbfeb85$export$5d9c34f69c80822b = (endpoint)=>new URL((0, $ElS14$discoveryPath), endpoint).toString();
|
|
50
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @param length The length of the raw random data.
|
|
35
|
+
*/ const $7faa35338215c9c1$var$generateRandomString = (length = 64)=>(0, $ElS14$fromUint8Array)(crypto.getRandomValues(new Uint8Array(length)), true);
|
|
36
|
+
const $7faa35338215c9c1$export$9ccd2716e53a229b = ()=>$7faa35338215c9c1$var$generateRandomString();
|
|
37
|
+
const $7faa35338215c9c1$export$cf1891f923f5943a = ()=>$7faa35338215c9c1$var$generateRandomString();
|
|
38
|
+
const $7faa35338215c9c1$export$414b01b1f867308a = async (codeVerifier)=>{
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
40
|
+
if (crypto.subtle === undefined) /**
|
|
41
|
+
* `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,
|
|
42
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle
|
|
43
|
+
* https://www.chromium.org/blink/webcrypto/#accessing-it
|
|
44
|
+
*/ throw new (0, $90df2ab0e44b5eba$re_export$LogtoError)("crypto_subtle_unavailable");
|
|
45
|
+
const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);
|
|
46
|
+
const codeChallenge = new Uint8Array(await crypto.subtle.digest("SHA-256", encodedCodeVerifier));
|
|
47
|
+
return (0, $ElS14$fromUint8Array)(codeChallenge, true);
|
|
48
|
+
};
|
|
51
49
|
|
|
52
50
|
|
|
53
51
|
|
|
54
|
-
const $90df2ab0e44b5eba$
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
prompt: logtoConfig.prompt ?? (0, $90df2ab0e44b5eba$import$5548085c5b0a2ee3$83716a4aa1642908).Consent,
|
|
68
|
-
scopes: (0, $ElS14$withReservedScopes)(logtoConfig.scopes).split(" ")
|
|
69
|
-
};
|
|
70
|
-
this.logtoStorageKey = (0, $2f0dba05fbbfeb85$export$bdf1d4f122e17e7b)(logtoConfig.appId);
|
|
71
|
-
this.requester = requester;
|
|
72
|
-
this._idToken = localStorage.getItem((0, $2f0dba05fbbfeb85$export$cdb4d35801155147)(this.logtoStorageKey));
|
|
73
|
-
}
|
|
74
|
-
get isAuthenticated() {
|
|
75
|
-
return Boolean(this.idToken);
|
|
76
|
-
}
|
|
77
|
-
get signInSession() {
|
|
78
|
-
const jsonItem = sessionStorage.getItem(this.logtoStorageKey);
|
|
79
|
-
if (!jsonItem) return null;
|
|
80
|
-
try {
|
|
81
|
-
const item = JSON.parse(jsonItem);
|
|
82
|
-
(0, $ElS14$assert)(item, $90df2ab0e44b5eba$export$7b65a75f516b80e1);
|
|
83
|
-
return item;
|
|
84
|
-
} catch (error) {
|
|
85
|
-
throw new (0, $092943c955830b14$export$877962ca249b8fc8)("sign_in_session.invalid", error);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
set signInSession(logtoSignInSessionItem) {
|
|
89
|
-
if (!logtoSignInSessionItem) {
|
|
90
|
-
sessionStorage.removeItem(this.logtoStorageKey);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const jsonItem = JSON.stringify(logtoSignInSessionItem);
|
|
94
|
-
sessionStorage.setItem(this.logtoStorageKey, jsonItem);
|
|
95
|
-
}
|
|
96
|
-
get refreshToken() {
|
|
97
|
-
return localStorage.getItem((0, $2f0dba05fbbfeb85$export$79da00f3c12fcb3c)(this.logtoStorageKey));
|
|
98
|
-
}
|
|
99
|
-
set refreshToken(refreshToken) {
|
|
100
|
-
const refreshTokenKey = (0, $2f0dba05fbbfeb85$export$79da00f3c12fcb3c)(this.logtoStorageKey);
|
|
101
|
-
if (!refreshToken) {
|
|
102
|
-
localStorage.removeItem(refreshTokenKey);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
localStorage.setItem(refreshTokenKey, refreshToken);
|
|
106
|
-
}
|
|
107
|
-
get idToken() {
|
|
108
|
-
return this._idToken;
|
|
109
|
-
}
|
|
110
|
-
set idToken(idToken) {
|
|
111
|
-
this._idToken = idToken;
|
|
112
|
-
const idTokenKey = (0, $2f0dba05fbbfeb85$export$cdb4d35801155147)(this.logtoStorageKey);
|
|
113
|
-
if (!idToken) {
|
|
114
|
-
localStorage.removeItem(idTokenKey);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
localStorage.setItem(idTokenKey, idToken);
|
|
118
|
-
}
|
|
119
|
-
// eslint-disable-next-line complexity
|
|
120
|
-
async getAccessToken(resource) {
|
|
121
|
-
if (!this.idToken) throw new (0, $092943c955830b14$export$877962ca249b8fc8)("not_authenticated");
|
|
122
|
-
const accessTokenKey = (0, $2f0dba05fbbfeb85$export$8f595bd2a47bcea6)(resource);
|
|
123
|
-
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
124
|
-
if (accessToken && accessToken.expiresAt > Date.now() / 1000) return accessToken.token;
|
|
125
|
-
// Since the access token has expired, delete it from the map.
|
|
126
|
-
if (accessToken) this.accessTokenMap.delete(accessTokenKey);
|
|
127
|
-
/**
|
|
128
|
-
* Need to fetch a new access token using refresh token.
|
|
129
|
-
* Reuse the cached promise if exists.
|
|
130
|
-
*/ const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);
|
|
131
|
-
if (cachedPromise) return cachedPromise;
|
|
132
|
-
/**
|
|
133
|
-
* Create a new promise and cache in map to avoid race condition.
|
|
134
|
-
* Since we enable "refresh token rotation" by default,
|
|
135
|
-
* it will be problematic when calling multiple `getAccessToken()` closely.
|
|
136
|
-
*/ const promise = this.getAccessTokenByRefreshToken(resource);
|
|
137
|
-
this.getAccessTokenPromiseMap.set(accessTokenKey, promise);
|
|
138
|
-
const token = await promise;
|
|
139
|
-
this.getAccessTokenPromiseMap.delete(accessTokenKey);
|
|
140
|
-
return token;
|
|
141
|
-
}
|
|
142
|
-
getIdTokenClaims() {
|
|
143
|
-
if (!this.idToken) throw new (0, $092943c955830b14$export$877962ca249b8fc8)("not_authenticated");
|
|
144
|
-
return (0, $ElS14$decodeIdToken)(this.idToken);
|
|
145
|
-
}
|
|
146
|
-
async signIn(redirectUri) {
|
|
147
|
-
const { appId: clientId , prompt: prompt , resources: resources , scopes: scopes } = this.logtoConfig;
|
|
148
|
-
const { authorizationEndpoint: authorizationEndpoint } = await this.getOidcConfig();
|
|
149
|
-
const codeVerifier = (0, $ElS14$generateCodeVerifier)();
|
|
150
|
-
const codeChallenge = await (0, $ElS14$generateCodeChallenge)(codeVerifier);
|
|
151
|
-
const state = (0, $ElS14$generateState)();
|
|
152
|
-
const signInUri = (0, $ElS14$generateSignInUri)({
|
|
153
|
-
authorizationEndpoint: authorizationEndpoint,
|
|
154
|
-
clientId: clientId,
|
|
155
|
-
redirectUri: redirectUri,
|
|
156
|
-
codeChallenge: codeChallenge,
|
|
157
|
-
state: state,
|
|
158
|
-
scopes: scopes,
|
|
159
|
-
resources: resources,
|
|
160
|
-
prompt: prompt
|
|
161
|
-
});
|
|
162
|
-
this.signInSession = {
|
|
163
|
-
redirectUri: redirectUri,
|
|
164
|
-
codeVerifier: codeVerifier,
|
|
165
|
-
state: state
|
|
166
|
-
};
|
|
167
|
-
this.refreshToken = null;
|
|
168
|
-
this.idToken = null;
|
|
169
|
-
window.location.assign(signInUri);
|
|
170
|
-
}
|
|
171
|
-
isSignInRedirected(url) {
|
|
172
|
-
const { signInSession: signInSession } = this;
|
|
173
|
-
if (!signInSession) return false;
|
|
174
|
-
const { redirectUri: redirectUri } = signInSession;
|
|
175
|
-
const { origin: origin , pathname: pathname } = new URL(url);
|
|
176
|
-
return `${origin}${pathname}` === redirectUri;
|
|
177
|
-
}
|
|
178
|
-
async handleSignInCallback(callbackUri) {
|
|
179
|
-
const { signInSession: signInSession , logtoConfig: logtoConfig , requester: requester } = this;
|
|
180
|
-
if (!signInSession) throw new (0, $092943c955830b14$export$877962ca249b8fc8)("sign_in_session.not_found");
|
|
181
|
-
const { redirectUri: redirectUri , state: state , codeVerifier: codeVerifier } = signInSession;
|
|
182
|
-
const code = (0, $ElS14$verifyAndParseCodeFromCallbackUri)(callbackUri, redirectUri, state);
|
|
183
|
-
const { appId: clientId } = logtoConfig;
|
|
184
|
-
const { tokenEndpoint: tokenEndpoint } = await this.getOidcConfig();
|
|
185
|
-
const codeTokenResponse = await (0, $ElS14$fetchTokenByAuthorizationCode)({
|
|
186
|
-
clientId: clientId,
|
|
187
|
-
tokenEndpoint: tokenEndpoint,
|
|
188
|
-
redirectUri: redirectUri,
|
|
189
|
-
codeVerifier: codeVerifier,
|
|
190
|
-
code: code
|
|
191
|
-
}, requester);
|
|
192
|
-
await this.verifyIdToken(codeTokenResponse.idToken);
|
|
193
|
-
this.saveCodeToken(codeTokenResponse);
|
|
194
|
-
this.signInSession = null;
|
|
195
|
-
}
|
|
196
|
-
async signOut(postLogoutRedirectUri) {
|
|
197
|
-
if (!this.idToken) throw new (0, $092943c955830b14$export$877962ca249b8fc8)("not_authenticated");
|
|
198
|
-
const { appId: clientId } = this.logtoConfig;
|
|
199
|
-
const { endSessionEndpoint: endSessionEndpoint , revocationEndpoint: revocationEndpoint } = await this.getOidcConfig();
|
|
200
|
-
if (this.refreshToken) try {
|
|
201
|
-
await (0, $ElS14$revoke)(revocationEndpoint, clientId, this.refreshToken, this.requester);
|
|
202
|
-
} catch {
|
|
203
|
-
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
204
|
-
}
|
|
205
|
-
const url = (0, $ElS14$generateSignOutUri)({
|
|
206
|
-
endSessionEndpoint: endSessionEndpoint,
|
|
207
|
-
postLogoutRedirectUri: postLogoutRedirectUri,
|
|
208
|
-
idToken: this.idToken
|
|
209
|
-
});
|
|
210
|
-
this.accessTokenMap.clear();
|
|
211
|
-
this.refreshToken = null;
|
|
212
|
-
this.idToken = null;
|
|
213
|
-
window.location.assign(url);
|
|
214
|
-
}
|
|
215
|
-
async getAccessTokenByRefreshToken(resource) {
|
|
216
|
-
if (!this.refreshToken) throw new (0, $092943c955830b14$export$877962ca249b8fc8)("not_authenticated");
|
|
217
|
-
try {
|
|
218
|
-
const accessTokenKey = (0, $2f0dba05fbbfeb85$export$8f595bd2a47bcea6)(resource);
|
|
219
|
-
const { appId: clientId } = this.logtoConfig;
|
|
220
|
-
const { tokenEndpoint: tokenEndpoint } = await this.getOidcConfig();
|
|
221
|
-
const { accessToken: accessToken , refreshToken: refreshToken , idToken: idToken , scope: scope , expiresIn: expiresIn } = await (0, $ElS14$fetchTokenByRefreshToken)({
|
|
222
|
-
clientId: clientId,
|
|
223
|
-
tokenEndpoint: tokenEndpoint,
|
|
224
|
-
refreshToken: this.refreshToken,
|
|
225
|
-
resource: resource,
|
|
226
|
-
scopes: resource ? [
|
|
227
|
-
"offline_access"
|
|
228
|
-
] : undefined
|
|
229
|
-
}, this.requester);
|
|
230
|
-
this.accessTokenMap.set(accessTokenKey, {
|
|
231
|
-
token: accessToken,
|
|
232
|
-
scope: scope,
|
|
233
|
-
expiresAt: Math.round(Date.now() / 1000) + expiresIn
|
|
234
|
-
});
|
|
235
|
-
this.refreshToken = refreshToken;
|
|
236
|
-
if (idToken) {
|
|
237
|
-
await this.verifyIdToken(idToken);
|
|
238
|
-
this.idToken = idToken;
|
|
239
|
-
}
|
|
240
|
-
return accessToken;
|
|
241
|
-
} catch (error) {
|
|
242
|
-
throw new (0, $092943c955830b14$export$877962ca249b8fc8)("get_access_token_by_refresh_token_failed", error);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
async _getOidcConfig() {
|
|
246
|
-
const { endpoint: endpoint } = this.logtoConfig;
|
|
247
|
-
const discoveryEndpoint = (0, $2f0dba05fbbfeb85$export$5d9c34f69c80822b)(endpoint);
|
|
248
|
-
return (0, $ElS14$fetchOidcConfig)(discoveryEndpoint, this.requester);
|
|
249
|
-
}
|
|
250
|
-
async _getJwtVerifyGetKey() {
|
|
251
|
-
const { jwksUri: jwksUri } = await this.getOidcConfig();
|
|
252
|
-
return (0, $ElS14$createRemoteJWKSet)(new URL(jwksUri));
|
|
253
|
-
}
|
|
254
|
-
async verifyIdToken(idToken) {
|
|
255
|
-
const { appId: appId } = this.logtoConfig;
|
|
256
|
-
const { issuer: issuer } = await this.getOidcConfig();
|
|
257
|
-
const jwtVerifyGetKey = await this.getJwtVerifyGetKey();
|
|
258
|
-
try {
|
|
259
|
-
await (0, $ElS14$verifyIdToken)(idToken, appId, issuer, jwtVerifyGetKey);
|
|
260
|
-
} catch (error) {
|
|
261
|
-
throw new (0, $092943c955830b14$export$877962ca249b8fc8)("invalid_id_token", error);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
saveCodeToken({ refreshToken: refreshToken , idToken: idToken , scope: scope , accessToken: accessToken , expiresIn: expiresIn }) {
|
|
265
|
-
this.refreshToken = refreshToken ?? null;
|
|
266
|
-
this.idToken = idToken;
|
|
267
|
-
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
268
|
-
const accessTokenKey = (0, $2f0dba05fbbfeb85$export$8f595bd2a47bcea6)();
|
|
269
|
-
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
270
|
-
this.accessTokenMap.set(accessTokenKey, {
|
|
271
|
-
token: accessToken,
|
|
272
|
-
scope: scope,
|
|
273
|
-
expiresAt: expiresAt
|
|
52
|
+
const $90df2ab0e44b5eba$var$navigate = (url)=>{
|
|
53
|
+
window.location.assign(url);
|
|
54
|
+
};
|
|
55
|
+
class $90df2ab0e44b5eba$export$2e2bcd8739ae039 extends (0, $ElS14$logtoclient) {
|
|
56
|
+
constructor(config){
|
|
57
|
+
const requester = (0, $ElS14$createRequester)(fetch);
|
|
58
|
+
super(config, {
|
|
59
|
+
requester: requester,
|
|
60
|
+
navigate: $90df2ab0e44b5eba$var$navigate,
|
|
61
|
+
storage: new (0, $283691d41cf73b69$export$2baa60fa09b100be)(config.appId),
|
|
62
|
+
generateCodeChallenge: $7faa35338215c9c1$export$414b01b1f867308a,
|
|
63
|
+
generateCodeVerifier: $7faa35338215c9c1$export$cf1891f923f5943a,
|
|
64
|
+
generateState: $7faa35338215c9c1$export$9ccd2716e53a229b
|
|
274
65
|
});
|
|
275
66
|
}
|
|
276
67
|
}
|
|
277
68
|
|
|
278
69
|
|
|
279
|
-
export {$90df2ab0e44b5eba$export$
|
|
70
|
+
export {$90df2ab0e44b5eba$export$2e2bcd8739ae039 as default, $90df2ab0e44b5eba$re_export$LogtoError as LogtoError, $90df2ab0e44b5eba$re_export$OidcError as OidcError, $90df2ab0e44b5eba$re_export$Prompt as Prompt, $90df2ab0e44b5eba$re_export$LogtoRequestError as LogtoRequestError, $90df2ab0e44b5eba$re_export$LogtoClientError as LogtoClientError, $90df2ab0e44b5eba$re_export$ReservedScope as ReservedScope, $90df2ab0e44b5eba$re_export$UserScope as UserScope};
|
|
280
71
|
//# sourceMappingURL=module.js.map
|
package/lib/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/browser/src/index.ts","packages/browser/src/errors.ts","packages/browser/src/utils/index.ts"],"sourcesContent":["import {\n CodeTokenResponse,\n createRequester,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n generateCodeChallenge,\n generateCodeVerifier,\n generateSignInUri,\n generateSignOutUri,\n generateState,\n IdTokenClaims,\n Prompt,\n Requester,\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, Infer, string, type } from 'superstruct';\n\nimport { LogtoClientError } from './errors';\nimport {\n buildAccessTokenKey,\n buildIdTokenKey,\n buildLogtoKey,\n buildRefreshTokenKey,\n getDiscoveryEndpoint,\n} from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode } from '@logto/js';\nexport { LogtoError, OidcError, Prompt } from '@logto/js';\nexport * from './errors';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n usingPersistStorage?: boolean;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number; // Unix Timestamp in seconds\n};\n\nexport const LogtoSignInSessionItemSchema = type({\n redirectUri: string(),\n codeVerifier: string(),\n state: string(),\n});\n\nexport type LogtoSignInSessionItem = Infer<typeof LogtoSignInSessionItemSchema>;\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 logtoStorageKey: string;\n protected readonly requester: Requester;\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, requester = createRequester()) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withReservedScopes(logtoConfig.scopes).split(' '),\n };\n this.logtoStorageKey = buildLogtoKey(logtoConfig.appId);\n this.requester = requester;\n this._idToken = localStorage.getItem(buildIdTokenKey(this.logtoStorageKey));\n }\n\n public get isAuthenticated() {\n return Boolean(this.idToken);\n }\n\n protected get signInSession(): Nullable<LogtoSignInSessionItem> {\n const jsonItem = sessionStorage.getItem(this.logtoStorageKey);\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 sessionStorage.removeItem(this.logtoStorageKey);\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n sessionStorage.setItem(this.logtoStorageKey, jsonItem);\n }\n\n get refreshToken() {\n return localStorage.getItem(buildRefreshTokenKey(this.logtoStorageKey));\n }\n\n private set refreshToken(refreshToken: Nullable<string>) {\n const refreshTokenKey = buildRefreshTokenKey(this.logtoStorageKey);\n\n if (!refreshToken) {\n localStorage.removeItem(refreshTokenKey);\n\n return;\n }\n\n localStorage.setItem(refreshTokenKey, 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 const idTokenKey = buildIdTokenKey(this.logtoStorageKey);\n\n if (!idToken) {\n localStorage.removeItem(idTokenKey);\n\n return;\n }\n\n localStorage.setItem(idTokenKey, 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 = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n const state = 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 window.location.assign(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, requester } = this;\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.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 window.location.assign(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.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\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.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 }\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 // TODO: linear issue LOG-1419\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 { discoveryPath } from '@logto/js';\n\nconst logtoStorageItemKeyPrefix = `logto`;\nexport const buildLogtoKey = (key: string): string => `${logtoStorageItemKeyPrefix}:${key}`;\nexport const buildRefreshTokenKey = (logtoKey: string) => `${logtoKey}:refreshToken`;\nexport const buildIdTokenKey = (logtoKey: string) => `${logtoKey}:idToken`;\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"],"names":[],"version":3,"file":"module.js.map"}
|
|
1
|
+
{"mappings":";;;AAAA;ACGO,MAAM,yCAAyB,GAAG,CAAC,KAAK,CAAC,AAAC;AAE1C,MAAM,yCAAc;IAGzB,YAAY,KAAa,CAAE;QACzB,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,yCAAyB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;KAC3D;IAED,MAAM,OAAO,CAAC,GAAe,EAA6B;QACxD,IAAI,GAAG,KAAK,eAAe,EACzB,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAGjD,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;KAC1D;IAED,MAAM,OAAO,CAAC,GAAe,EAAE,KAAa,EAAiB;QAC3D,IAAI,GAAG,KAAK,eAAe,EAAE;YAC3B,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAE/C,OAAO;SACR;QACD,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;KAC1D;IAED,MAAM,UAAU,CAAC,GAAe,EAAiB;QAC/C,IAAI,GAAG,KAAK,eAAe,EAAE;YAC3B,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAE3C,OAAO;SACR;QACD,YAAY,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;KACtD;CACF;;;ACnCD;;AAGA;;GAEG,CACH,MAAM,0CAAoB,GAAG,CAAC,MAAM,GAAG,EAAE,GACvC,CAAA,GAAA,qBAAc,CAAA,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,AAAC;AAKhE,MAAM,yCAAa,GAAG,IAAM,0CAAoB,EAAE,AAAC;AAOnD,MAAM,yCAAoB,GAAG,IAAM,0CAAoB,EAAE,AAAC;AAQ1D,MAAM,yCAAqB,GAAG,OAAO,YAAoB,GAAsB;IACpF,uEAAuE;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAC7B;;;;OAIG,CACH,MAAM,IAAI,CAAA,GAAA,sCAAU,CAAA,CAAC,2BAA2B,CAAC,CAAC;IAGpD,MAAM,mBAAmB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,AAAC;IACnE,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC,AAAC;IAEjG,OAAO,CAAA,GAAA,qBAAc,CAAA,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;CAC5C,AAAC;;;;AFrBF,MAAM,8BAAQ,GAAG,CAAC,GAAW,GAAK;IAChC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;CAC7B,AAAC;AAEa,uDAA0B,CAAA,GAAA,kBAAU,CAAA;IACjD,YAAY,MAAmB,CAAE;QAC/B,MAAM,SAAS,GAAG,CAAA,GAAA,sBAAe,CAAA,CAAC,KAAK,CAAC,AAAC;QACzC,KAAK,CAAC,MAAM,EAAE;uBACZ,SAAS;sBACT,8BAAQ;YACR,OAAO,EAAE,IAAI,CAAA,GAAA,yCAAc,CAAA,CAAC,MAAM,CAAC,KAAK,CAAC;mCACzC,yCAAqB;kCACrB,yCAAoB;2BACpB,yCAAa;SACd,CAAC,CAAC;KACJ;CACF","sources":["packages/browser/src/index.ts","packages/browser/src/storage.ts","packages/browser/src/utils/generators.ts"],"sourcesContent":["import BaseClient, { createRequester, LogtoConfig } from '@logto/client';\n\nimport { BrowserStorage } from './storage';\nimport { generateCodeChallenge, generateCodeVerifier, generateState } from './utils/generators';\n\nexport type {\n IdTokenClaims,\n LogtoErrorCode,\n LogtoConfig,\n LogtoClientErrorCode,\n UserInfoResponse,\n} from '@logto/client';\n\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n LogtoClientError,\n ReservedScope,\n UserScope,\n} from '@logto/client';\n\nconst navigate = (url: string) => {\n window.location.assign(url);\n};\n\nexport default class LogtoClient extends BaseClient {\n constructor(config: LogtoConfig) {\n const requester = createRequester(fetch);\n super(config, {\n requester,\n navigate,\n storage: new BrowserStorage(config.appId),\n generateCodeChallenge,\n generateCodeVerifier,\n generateState,\n });\n }\n}\n","import { Storage, StorageKey } from '@logto/client';\nimport { Nullable } from '@silverhand/essentials';\n\nexport const logtoStorageItemKeyPrefix = `logto`;\n\nexport class BrowserStorage implements Storage {\n private readonly storageKey: string;\n\n constructor(appId: string) {\n this.storageKey = `${logtoStorageItemKeyPrefix}:${appId}`;\n }\n\n async getItem(key: StorageKey): Promise<Nullable<string>> {\n if (key === 'signInSession') {\n return sessionStorage.getItem(this.storageKey);\n }\n\n return localStorage.getItem(`${this.storageKey}:${key}`);\n }\n\n async setItem(key: StorageKey, value: string): Promise<void> {\n if (key === 'signInSession') {\n sessionStorage.setItem(this.storageKey, value);\n\n return;\n }\n localStorage.setItem(`${this.storageKey}:${key}`, value);\n }\n\n async removeItem(key: StorageKey): Promise<void> {\n if (key === 'signInSession') {\n sessionStorage.removeItem(this.storageKey);\n\n return;\n }\n localStorage.removeItem(`${this.storageKey}:${key}`);\n }\n}\n","/** @link [Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) */\n\nimport { LogtoError } from '@logto/client';\nimport { fromUint8Array } from 'js-base64';\n\n/**\n * @param length The length of the raw random data.\n */\nconst generateRandomString = (length = 64) =>\n fromUint8Array(crypto.getRandomValues(new Uint8Array(length)), true);\n\n/**\n * Generates random string for state and encodes them in url safe base64\n */\nexport const generateState = () => generateRandomString();\n\n/**\n * Generates code verifier\n *\n * @link [Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1)\n */\nexport const generateCodeVerifier = () => generateRandomString();\n\n/**\n * Calculates the S256 PKCE code challenge for an arbitrary code verifier and encodes it in url safe base64\n *\n * @param {String} codeVerifier Code verifier to calculate the S256 code challenge for\n * @link [Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2)\n */\nexport const generateCodeChallenge = async (codeVerifier: string): Promise<string> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (crypto.subtle === undefined) {\n /**\n * `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,\n * https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle\n * https://www.chromium.org/blink/webcrypto/#accessing-it\n */\n throw new LogtoError('crypto_subtle_unavailable');\n }\n\n const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);\n const codeChallenge = new Uint8Array(await crypto.subtle.digest('SHA-256', encodedCodeVerifier));\n\n return fromUint8Array(codeChallenge, true);\n};\n"],"names":[],"version":3,"file":"module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/browser",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
4
4
|
"source": "./src/index.ts",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -29,33 +29,29 @@
|
|
|
29
29
|
"prepack": "pnpm test"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@logto/
|
|
33
|
-
"@silverhand/essentials": "^1.1
|
|
34
|
-
"
|
|
35
|
-
"lodash.get": "^4.4.2",
|
|
36
|
-
"lodash.once": "^4.1.1",
|
|
37
|
-
"superstruct": "^0.16.0"
|
|
32
|
+
"@logto/client": "^1.0.0-beta.10",
|
|
33
|
+
"@silverhand/essentials": "^1.2.1",
|
|
34
|
+
"js-base64": "^3.7.2"
|
|
38
35
|
},
|
|
39
36
|
"devDependencies": {
|
|
40
37
|
"@jest/types": "^27.5.1",
|
|
41
|
-
"@parcel/core": "^2.
|
|
42
|
-
"@parcel/packager-ts": "^2.
|
|
43
|
-
"@parcel/transformer-typescript-types": "^2.
|
|
44
|
-
"@silverhand/eslint-config": "^0.
|
|
45
|
-
"@silverhand/ts-config": "^0.
|
|
38
|
+
"@parcel/core": "^2.7.0",
|
|
39
|
+
"@parcel/packager-ts": "^2.7.0",
|
|
40
|
+
"@parcel/transformer-typescript-types": "^2.7.0",
|
|
41
|
+
"@silverhand/eslint-config": "^1.0.0",
|
|
42
|
+
"@silverhand/ts-config": "^1.0.0",
|
|
46
43
|
"@types/jest": "^27.4.0",
|
|
47
|
-
"
|
|
48
|
-
"@types/lodash.once": "^4.1.6",
|
|
49
|
-
"eslint": "^8.9.0",
|
|
44
|
+
"eslint": "^8.23.0",
|
|
50
45
|
"jest": "^27.5.1",
|
|
51
46
|
"jest-location-mock": "^1.0.9",
|
|
52
47
|
"jest-matcher-specific-error": "^1.0.0",
|
|
53
48
|
"lint-staged": "^13.0.0",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
49
|
+
"node-fetch": "^2.6.7",
|
|
50
|
+
"parcel": "^2.7.0",
|
|
51
|
+
"prettier": "^2.7.1",
|
|
56
52
|
"text-encoder": "^0.0.4",
|
|
57
53
|
"ts-jest": "^27.0.4",
|
|
58
|
-
"typescript": "
|
|
54
|
+
"typescript": "4.7.4"
|
|
59
55
|
},
|
|
60
56
|
"eslintConfig": {
|
|
61
57
|
"extends": "@silverhand"
|
|
@@ -64,5 +60,5 @@
|
|
|
64
60
|
"publishConfig": {
|
|
65
61
|
"access": "public"
|
|
66
62
|
},
|
|
67
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "c79c3759b7f15c44bf5b476dcebd82e9c96e9dd8"
|
|
68
64
|
}
|