@logto/client 1.0.0-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -53,8 +53,7 @@ export type LogtoSignInSessionItem = {
53
53
  };
54
54
  export const createRequester: (fetchFunction: typeof fetch) => Requester;
55
55
  export type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';
56
- export { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';
57
- export { ReservedScope, UserScope } from '@logto/core-kit';
56
+ export { LogtoError, OidcError, Prompt, LogtoRequestError, ReservedScope, UserScope, } from '@logto/js';
58
57
  export default class LogtoClient {
59
58
  protected readonly logtoConfig: LogtoConfig;
60
59
  protected readonly getOidcConfig: () => Promise<import("@silverhand/essentials").KeysToCamelCase<import("@logto/js").OidcConfigSnakeCaseResponse>>;
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/client/src/src/adapter.ts","packages/client/src/src/errors.ts","packages/client/src/src/types/index.ts","packages/client/src/src/utils/requester.ts","packages/client/src/src/utils/index.ts","packages/client/src/src/index.ts","packages/client/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,"/* eslint-disable max-lines */\nimport { ReservedScope } from '@logto/core-kit';\nimport {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n UserInfoResponse,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n isLogtoAccessTokenMap,\n isLogtoSignInSessionItem,\n LogtoConfig,\n LogtoSignInSessionItem,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\nexport { ReservedScope, UserScope } from '@logto/core-kit';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? [ReservedScope.OfflineAccess] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n/* eslint-enable max-lines */\n"],"names":[],"version":3,"file":"index.d.ts.map"}
1
+ {"mappings":"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","sources":["packages/client/src/src/adapter.ts","packages/client/src/src/errors.ts","packages/client/src/src/types/index.ts","packages/client/src/src/utils/requester.ts","packages/client/src/src/utils/index.ts","packages/client/src/src/index.ts","packages/client/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,"import type { CodeTokenResponse, IdTokenClaims, UserInfoResponse } from '@logto/js';\nimport {\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport type { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport type { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types';\nimport { isLogtoAccessTokenMap, isLogtoSignInSessionItem } from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n ReservedScope,\n UserScope,\n} from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n */\n return this.getAccessTokenByRefreshToken(resource);\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n clientId,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n await this.adapter.storage.removeItem('accessToken');\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n // FIXME: @charles @sijie\n}\n"],"names":[],"version":3,"file":"index.d.ts.map"}
package/lib/index.js CHANGED
@@ -1,4 +1,3 @@
1
- var $4R6L3$logtocorekit = require("@logto/core-kit");
2
1
  var $4R6L3$logtojs = require("@logto/js");
3
2
  var $4R6L3$jose = require("jose");
4
3
  var $4R6L3$lodashonce = require("lodash.once");
@@ -10,9 +9,6 @@ function $parcel$interopDefault(a) {
10
9
  function $parcel$defineInteropFlag(a) {
11
10
  Object.defineProperty(a, '__esModule', {value: true, configurable: true});
12
11
  }
13
- function $parcel$export(e, n, v, s) {
14
- Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
15
- }
16
12
  function $parcel$exportWildcard(dest, source) {
17
13
  Object.keys(source).forEach(function(key) {
18
14
  if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {
@@ -29,6 +25,9 @@ function $parcel$exportWildcard(dest, source) {
29
25
 
30
26
  return dest;
31
27
  }
28
+ function $parcel$export(e, n, v, s) {
29
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
30
+ }
32
31
 
33
32
  $parcel$defineInteropFlag(module.exports);
34
33
 
@@ -37,10 +36,9 @@ $parcel$export(module.exports, "LogtoError", () => $f73788ae50447ce9$re_export$L
37
36
  $parcel$export(module.exports, "OidcError", () => $f73788ae50447ce9$re_export$OidcError);
38
37
  $parcel$export(module.exports, "Prompt", () => $4R6L3$logtojs.Prompt);
39
38
  $parcel$export(module.exports, "LogtoRequestError", () => $f73788ae50447ce9$re_export$LogtoRequestError);
40
- $parcel$export(module.exports, "createRequester", () => $b455f57f80fbf6bf$export$8d54726fdbf08e0a);
41
- $parcel$export(module.exports, "ReservedScope", () => $4R6L3$logtocorekit.ReservedScope);
39
+ $parcel$export(module.exports, "ReservedScope", () => $f73788ae50447ce9$re_export$ReservedScope);
42
40
  $parcel$export(module.exports, "UserScope", () => $f73788ae50447ce9$re_export$UserScope);
43
-
41
+ $parcel$export(module.exports, "createRequester", () => $b455f57f80fbf6bf$export$8d54726fdbf08e0a);
44
42
 
45
43
 
46
44
 
@@ -120,12 +118,10 @@ const $e2aabdbdb3cc09f0$export$5d9c34f69c80822b = (endpoint)=>new URL((0, $4R6L3
120
118
 
121
119
 
122
120
 
123
-
124
121
  class $f73788ae50447ce9$export$2e2bcd8739ae039 {
125
122
  getOidcConfig = (0, ($parcel$interopDefault($4R6L3$lodashonce)))(this._getOidcConfig);
126
123
  getJwtVerifyGetKey = (0, ($parcel$interopDefault($4R6L3$lodashonce)))(this._getJwtVerifyGetKey);
127
124
  accessTokenMap = new Map();
128
- getAccessTokenPromiseMap = new Map();
129
125
  constructor(logtoConfig, adapter){
130
126
  this.logtoConfig = {
131
127
  ...logtoConfig,
@@ -144,7 +140,6 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
144
140
  async getIdToken() {
145
141
  return this.adapter.storage.getItem("idToken");
146
142
  }
147
- // eslint-disable-next-line complexity
148
143
  async getAccessToken(resource) {
149
144
  if (!await this.getIdToken()) throw new (0, $9166104b36889c59$export$877962ca249b8fc8)("not_authenticated");
150
145
  const accessTokenKey = (0, $e2aabdbdb3cc09f0$export$8f595bd2a47bcea6)(resource);
@@ -154,18 +149,7 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
154
149
  if (accessToken) this.accessTokenMap.delete(accessTokenKey);
155
150
  /**
156
151
  * Need to fetch a new access token using refresh token.
157
- * Reuse the cached promise if exists.
158
- */ const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);
159
- if (cachedPromise) return cachedPromise;
160
- /**
161
- * Create a new promise and cache in map to avoid race condition.
162
- * Since we enable "refresh token rotation" by default,
163
- * it will be problematic when calling multiple `getAccessToken()` closely.
164
- */ const promise = this.getAccessTokenByRefreshToken(resource);
165
- this.getAccessTokenPromiseMap.set(accessTokenKey, promise);
166
- const token = await promise;
167
- this.getAccessTokenPromiseMap.delete(accessTokenKey);
168
- return token;
152
+ */ return this.getAccessTokenByRefreshToken(resource);
169
153
  }
170
154
  async getIdTokenClaims() {
171
155
  const idToken = await this.getIdToken();
@@ -244,11 +228,12 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
244
228
  const url = (0, $4R6L3$logtojs.generateSignOutUri)({
245
229
  endSessionEndpoint: endSessionEndpoint,
246
230
  postLogoutRedirectUri: postLogoutRedirectUri,
247
- idToken: idToken
231
+ clientId: clientId
248
232
  });
249
233
  this.accessTokenMap.clear();
250
234
  await this.setRefreshToken(null);
251
235
  await this.setIdToken(null);
236
+ await this.adapter.storage.removeItem("accessToken");
252
237
  this.adapter.navigate(url);
253
238
  }
254
239
  async getSignInSession() {
@@ -291,10 +276,7 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
291
276
  clientId: clientId,
292
277
  tokenEndpoint: tokenEndpoint,
293
278
  refreshToken: currentRefreshToken,
294
- resource: resource,
295
- scopes: resource ? [
296
- (0, $4R6L3$logtocorekit.ReservedScope).OfflineAccess
297
- ] : undefined
279
+ resource: resource
298
280
  }, this.adapter.requester);
299
281
  this.accessTokenMap.set(accessTokenKey, {
300
282
  token: accessToken,
@@ -360,7 +342,7 @@ class $f73788ae50447ce9$export$2e2bcd8739ae039 {
360
342
  for (const [key, accessToken] of Object.entries(json))this.accessTokenMap.set(key, accessToken);
361
343
  } catch {}
362
344
  }
363
- } /* eslint-enable max-lines */
345
+ }
364
346
  $parcel$exportWildcard(module.exports, $9166104b36889c59$exports);
365
347
  $parcel$exportWildcard(module.exports, $6d3989f7f53311af$exports);
366
348
 
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { ReservedScope } from '@logto/core-kit';\nimport {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n UserInfoResponse,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n isLogtoAccessTokenMap,\n isLogtoSignInSessionItem,\n LogtoConfig,\n LogtoSignInSessionItem,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\nexport { ReservedScope, UserScope } from '@logto/core-kit';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? [ReservedScope.OfflineAccess] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n/* eslint-enable max-lines */\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 fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { isArbitraryObject, Prompt } from '@logto/js';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number;\n};\n\nexport const isLogtoSignInSessionItem = (data: unknown): data is LogtoSignInSessionItem => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');\n};\n\nexport const isLogtoAccessTokenMap = (data: unknown): data is Record<string, AccessToken> => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return Object.values(data).every((value) => {\n if (!isArbitraryObject(value)) {\n return false;\n }\n\n return (\n typeof value.token === 'string' &&\n typeof value.scope === 'string' &&\n typeof value.expiresAt === 'number'\n );\n });\n};\n\nexport type LogtoSignInSessionItem = {\n redirectUri: string;\n codeVerifier: string;\n state: string;\n};\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoError, LogtoRequestError, isLogtoRequestError, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!isLogtoRequestError(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"index.js.map"}
1
+ {"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import type { CodeTokenResponse, IdTokenClaims, UserInfoResponse } from '@logto/js';\nimport {\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport type { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport type { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types';\nimport { isLogtoAccessTokenMap, isLogtoSignInSessionItem } from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n ReservedScope,\n UserScope,\n} from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n */\n return this.getAccessTokenByRefreshToken(resource);\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n clientId,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n await this.adapter.storage.removeItem('accessToken');\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n // FIXME: @charles @sijie\n}\n","import type { 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 fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import type { Prompt } from '@logto/js';\nimport { isArbitraryObject } from '@logto/js';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number;\n};\n\nexport const isLogtoSignInSessionItem = (data: unknown): data is LogtoSignInSessionItem => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');\n};\n\nexport const isLogtoAccessTokenMap = (data: unknown): data is Record<string, AccessToken> => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return Object.values(data).every((value) => {\n if (!isArbitraryObject(value)) {\n return false;\n }\n\n return (\n typeof value.token === 'string' &&\n typeof value.scope === 'string' &&\n typeof value.expiresAt === 'number'\n );\n });\n};\n\nexport type LogtoSignInSessionItem = {\n redirectUri: string;\n codeVerifier: string;\n state: string;\n};\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import type { Requester } from '@logto/js';\nimport { LogtoError, LogtoRequestError, isLogtoRequestError } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!isLogtoRequestError(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"index.js.map"}
@@ -0,0 +1,78 @@
1
+ import { Requester, Prompt, IdTokenClaims, UserInfoResponse } from "@logto/js";
2
+ import { Nullable, NormalizeKeyPaths } from "@silverhand/essentials";
3
+ export type StorageKey = 'idToken' | 'refreshToken' | 'accessToken' | 'signInSession';
4
+ export type Storage = {
5
+ getItem(key: StorageKey): Promise<Nullable<string>>;
6
+ setItem(key: StorageKey, value: string): Promise<void>;
7
+ removeItem(key: StorageKey): Promise<void>;
8
+ };
9
+ type Navigate = (url: string) => void;
10
+ export type ClientAdapter = {
11
+ requester: Requester;
12
+ storage: Storage;
13
+ navigate: Navigate;
14
+ generateState: () => string;
15
+ generateCodeVerifier: () => string;
16
+ generateCodeChallenge: (codeVerifier: string) => Promise<string>;
17
+ };
18
+ declare const logtoClientErrorCodes: Readonly<{
19
+ sign_in_session: {
20
+ invalid: string;
21
+ not_found: string;
22
+ };
23
+ not_authenticated: "Not authenticated.";
24
+ get_access_token_by_refresh_token_failed: "Failed to get access token by refresh token.";
25
+ fetch_user_info_failed: "Unable to fetch user info. The access token may be invalid.";
26
+ invalid_id_token: "Invalid id token.";
27
+ }>;
28
+ export type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;
29
+ export class LogtoClientError extends Error {
30
+ code: LogtoClientErrorCode;
31
+ data: unknown;
32
+ constructor(code: LogtoClientErrorCode, data?: unknown);
33
+ }
34
+ export type LogtoConfig = {
35
+ endpoint: string;
36
+ appId: string;
37
+ appSecret?: string;
38
+ scopes?: string[];
39
+ resources?: string[];
40
+ prompt?: Prompt;
41
+ };
42
+ export type AccessToken = {
43
+ token: string;
44
+ scope: string;
45
+ expiresAt: number;
46
+ };
47
+ export const isLogtoSignInSessionItem: (data: unknown) => data is LogtoSignInSessionItem;
48
+ export const isLogtoAccessTokenMap: (data: unknown) => data is Record<string, AccessToken>;
49
+ export type LogtoSignInSessionItem = {
50
+ redirectUri: string;
51
+ codeVerifier: string;
52
+ state: string;
53
+ };
54
+ export const createRequester: (fetchFunction: typeof fetch) => Requester;
55
+ export type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';
56
+ export { LogtoError, OidcError, Prompt, LogtoRequestError, ReservedScope, UserScope, } from '@logto/js';
57
+ export default class LogtoClient {
58
+ protected readonly logtoConfig: LogtoConfig;
59
+ protected readonly getOidcConfig: () => Promise<import("@silverhand/essentials").KeysToCamelCase<import("@logto/js").OidcConfigSnakeCaseResponse>>;
60
+ protected readonly getJwtVerifyGetKey: () => Promise<import("jose/dist/types/types").GetKeyFunction<import("jose").JWSHeaderParameters, import("jose").FlattenedJWSInput>>;
61
+ protected readonly adapter: ClientAdapter;
62
+ protected readonly accessTokenMap: Map<string, AccessToken>;
63
+ constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter);
64
+ isAuthenticated(): Promise<boolean>;
65
+ getRefreshToken(): Promise<Nullable<string>>;
66
+ getIdToken(): Promise<Nullable<string>>;
67
+ getAccessToken(resource?: string): Promise<string>;
68
+ getIdTokenClaims(): Promise<IdTokenClaims>;
69
+ fetchUserInfo(): Promise<UserInfoResponse>;
70
+ signIn(redirectUri: string): Promise<void>;
71
+ isSignInRedirected(url: string): Promise<boolean>;
72
+ handleSignInCallback(callbackUri: string): Promise<void>;
73
+ signOut(postLogoutRedirectUri?: string): Promise<void>;
74
+ protected getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>>;
75
+ protected setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>): Promise<void>;
76
+ }
77
+
78
+ //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,4 @@
1
- import {ReservedScope as $19775a679e2952df$import$2bf383245f9cd522$1d2e82cebfd4b08, UserScope as $19775a679e2952df$re_export$UserScope} from "@logto/core-kit";
2
- import {Prompt as $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908, withDefaultScopes as $kqBTI$withDefaultScopes, decodeIdToken as $kqBTI$decodeIdToken, fetchUserInfo as $kqBTI$fetchUserInfo, generateSignInUri as $kqBTI$generateSignInUri, verifyAndParseCodeFromCallbackUri as $kqBTI$verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode as $kqBTI$fetchTokenByAuthorizationCode, revoke as $kqBTI$revoke, generateSignOutUri as $kqBTI$generateSignOutUri, fetchTokenByRefreshToken as $kqBTI$fetchTokenByRefreshToken, fetchOidcConfig as $kqBTI$fetchOidcConfig, verifyIdToken as $kqBTI$verifyIdToken, LogtoError as $19775a679e2952df$re_export$LogtoError, OidcError as $19775a679e2952df$re_export$OidcError, LogtoRequestError as $19775a679e2952df$re_export$LogtoRequestError, isArbitraryObject as $kqBTI$isArbitraryObject, discoveryPath as $kqBTI$discoveryPath, isLogtoRequestError as $kqBTI$isLogtoRequestError} from "@logto/js";
1
+ import {Prompt as $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908, withDefaultScopes as $kqBTI$withDefaultScopes, decodeIdToken as $kqBTI$decodeIdToken, fetchUserInfo as $kqBTI$fetchUserInfo, generateSignInUri as $kqBTI$generateSignInUri, verifyAndParseCodeFromCallbackUri as $kqBTI$verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode as $kqBTI$fetchTokenByAuthorizationCode, revoke as $kqBTI$revoke, generateSignOutUri as $kqBTI$generateSignOutUri, fetchTokenByRefreshToken as $kqBTI$fetchTokenByRefreshToken, fetchOidcConfig as $kqBTI$fetchOidcConfig, verifyIdToken as $kqBTI$verifyIdToken, LogtoError as $19775a679e2952df$re_export$LogtoError, OidcError as $19775a679e2952df$re_export$OidcError, LogtoRequestError as $19775a679e2952df$re_export$LogtoRequestError, ReservedScope as $19775a679e2952df$re_export$ReservedScope, UserScope as $19775a679e2952df$re_export$UserScope, isArbitraryObject as $kqBTI$isArbitraryObject, discoveryPath as $kqBTI$discoveryPath, isLogtoRequestError as $kqBTI$isLogtoRequestError} from "@logto/js";
3
2
  import {createRemoteJWKSet as $kqBTI$createRemoteJWKSet} from "jose";
4
3
  import $kqBTI$lodashonce from "lodash.once";
5
4
  import $kqBTI$lodashget from "lodash.get";
@@ -10,7 +9,6 @@ function $parcel$export(e, n, v, s) {
10
9
 
11
10
 
12
11
 
13
-
14
12
  var $4ec05cedcef20733$exports = {};
15
13
 
16
14
  $parcel$export($4ec05cedcef20733$exports, "LogtoClientError", () => $4ec05cedcef20733$export$877962ca249b8fc8);
@@ -87,12 +85,10 @@ const $dcfd5d64758ae70b$export$5d9c34f69c80822b = (endpoint)=>new URL((0, $kqBTI
87
85
 
88
86
 
89
87
 
90
-
91
88
  class $19775a679e2952df$export$2e2bcd8739ae039 {
92
89
  getOidcConfig = (0, $kqBTI$lodashonce)(this._getOidcConfig);
93
90
  getJwtVerifyGetKey = (0, $kqBTI$lodashonce)(this._getJwtVerifyGetKey);
94
91
  accessTokenMap = new Map();
95
- getAccessTokenPromiseMap = new Map();
96
92
  constructor(logtoConfig, adapter){
97
93
  this.logtoConfig = {
98
94
  ...logtoConfig,
@@ -111,7 +107,6 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
111
107
  async getIdToken() {
112
108
  return this.adapter.storage.getItem("idToken");
113
109
  }
114
- // eslint-disable-next-line complexity
115
110
  async getAccessToken(resource) {
116
111
  if (!await this.getIdToken()) throw new (0, $4ec05cedcef20733$export$877962ca249b8fc8)("not_authenticated");
117
112
  const accessTokenKey = (0, $dcfd5d64758ae70b$export$8f595bd2a47bcea6)(resource);
@@ -121,18 +116,7 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
121
116
  if (accessToken) this.accessTokenMap.delete(accessTokenKey);
122
117
  /**
123
118
  * Need to fetch a new access token using refresh token.
124
- * Reuse the cached promise if exists.
125
- */ const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);
126
- if (cachedPromise) return cachedPromise;
127
- /**
128
- * Create a new promise and cache in map to avoid race condition.
129
- * Since we enable "refresh token rotation" by default,
130
- * it will be problematic when calling multiple `getAccessToken()` closely.
131
- */ const promise = this.getAccessTokenByRefreshToken(resource);
132
- this.getAccessTokenPromiseMap.set(accessTokenKey, promise);
133
- const token = await promise;
134
- this.getAccessTokenPromiseMap.delete(accessTokenKey);
135
- return token;
119
+ */ return this.getAccessTokenByRefreshToken(resource);
136
120
  }
137
121
  async getIdTokenClaims() {
138
122
  const idToken = await this.getIdToken();
@@ -211,11 +195,12 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
211
195
  const url = (0, $kqBTI$generateSignOutUri)({
212
196
  endSessionEndpoint: endSessionEndpoint,
213
197
  postLogoutRedirectUri: postLogoutRedirectUri,
214
- idToken: idToken
198
+ clientId: clientId
215
199
  });
216
200
  this.accessTokenMap.clear();
217
201
  await this.setRefreshToken(null);
218
202
  await this.setIdToken(null);
203
+ await this.adapter.storage.removeItem("accessToken");
219
204
  this.adapter.navigate(url);
220
205
  }
221
206
  async getSignInSession() {
@@ -258,10 +243,7 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
258
243
  clientId: clientId,
259
244
  tokenEndpoint: tokenEndpoint,
260
245
  refreshToken: currentRefreshToken,
261
- resource: resource,
262
- scopes: resource ? [
263
- (0, $19775a679e2952df$import$2bf383245f9cd522$1d2e82cebfd4b08).OfflineAccess
264
- ] : undefined
246
+ resource: resource
265
247
  }, this.adapter.requester);
266
248
  this.accessTokenMap.set(accessTokenKey, {
267
249
  token: accessToken,
@@ -327,8 +309,8 @@ class $19775a679e2952df$export$2e2bcd8739ae039 {
327
309
  for (const [key, accessToken] of Object.entries(json))this.accessTokenMap.set(key, accessToken);
328
310
  } catch {}
329
311
  }
330
- } /* eslint-enable max-lines */
312
+ }
331
313
 
332
314
 
333
- export {$19775a679e2952df$export$2e2bcd8739ae039 as default, $19775a679e2952df$re_export$LogtoError as LogtoError, $19775a679e2952df$re_export$OidcError as OidcError, $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908 as Prompt, $19775a679e2952df$re_export$LogtoRequestError as LogtoRequestError, $8449a5dbad0d6387$export$8d54726fdbf08e0a as createRequester, $19775a679e2952df$import$2bf383245f9cd522$1d2e82cebfd4b08 as ReservedScope, $19775a679e2952df$re_export$UserScope as UserScope, $4ec05cedcef20733$export$877962ca249b8fc8 as LogtoClientError, $50f2bb780a45e70c$export$5d8adf6e063019de as isLogtoSignInSessionItem, $50f2bb780a45e70c$export$c12fab42a9a3e2a6 as isLogtoAccessTokenMap};
334
- //# sourceMappingURL=module.js.map
315
+ export {$19775a679e2952df$export$2e2bcd8739ae039 as default, $19775a679e2952df$re_export$LogtoError as LogtoError, $19775a679e2952df$re_export$OidcError as OidcError, $19775a679e2952df$import$5548085c5b0a2ee3$83716a4aa1642908 as Prompt, $19775a679e2952df$re_export$LogtoRequestError as LogtoRequestError, $19775a679e2952df$re_export$ReservedScope as ReservedScope, $19775a679e2952df$re_export$UserScope as UserScope, $8449a5dbad0d6387$export$8d54726fdbf08e0a as createRequester, $4ec05cedcef20733$export$877962ca249b8fc8 as LogtoClientError, $50f2bb780a45e70c$export$5d8adf6e063019de as isLogtoSignInSessionItem, $50f2bb780a45e70c$export$c12fab42a9a3e2a6 as isLogtoAccessTokenMap};
316
+ //# sourceMappingURL=module.mjs.map
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["import type { CodeTokenResponse, IdTokenClaims, UserInfoResponse } from '@logto/js';\nimport {\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n Prompt,\n revoke,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport type { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport type { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types';\nimport { isLogtoAccessTokenMap, isLogtoSignInSessionItem } from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport {\n LogtoError,\n OidcError,\n Prompt,\n LogtoRequestError,\n ReservedScope,\n UserScope,\n} from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n */\n return this.getAccessTokenByRefreshToken(resource);\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n clientId,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n await this.adapter.storage.removeItem('accessToken');\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n // FIXME: @charles @sijie\n}\n","import type { 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 fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import type { Prompt } from '@logto/js';\nimport { isArbitraryObject } from '@logto/js';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number;\n};\n\nexport const isLogtoSignInSessionItem = (data: unknown): data is LogtoSignInSessionItem => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');\n};\n\nexport const isLogtoAccessTokenMap = (data: unknown): data is Record<string, AccessToken> => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return Object.values(data).every((value) => {\n if (!isArbitraryObject(value)) {\n return false;\n }\n\n return (\n typeof value.token === 'string' &&\n typeof value.scope === 'string' &&\n typeof value.expiresAt === 'number'\n );\n });\n};\n\nexport type LogtoSignInSessionItem = {\n redirectUri: string;\n codeVerifier: string;\n state: string;\n};\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import type { Requester } from '@logto/js';\nimport { LogtoError, LogtoRequestError, isLogtoRequestError } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!isLogtoRequestError(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"module.mjs.map"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@logto/client",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.0",
4
4
  "source": "./src/index.ts",
5
5
  "main": "./lib/index.js",
6
6
  "exports": {
7
7
  "require": "./lib/index.js",
8
- "import": "./lib/module.js"
8
+ "import": "./lib/module.mjs"
9
9
  },
10
- "module": "./lib/module.js",
10
+ "module": "./lib/module.mjs",
11
11
  "types": "./lib/index.d.ts",
12
12
  "files": [
13
13
  "lib"
@@ -22,15 +22,14 @@
22
22
  "dev:tsc": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
23
23
  "precommit": "lint-staged",
24
24
  "check": "tsc --noEmit",
25
- "build": "rm -rf lib/ && pnpm check && parcel build",
25
+ "build": "rm -rf lib/ && pnpm check && parcel build && cp lib/index.d.ts lib/module.d.mts",
26
26
  "lint": "eslint --ext .ts src",
27
27
  "test": "jest",
28
28
  "test:coverage": "jest --silent --env=jsdom && jest --silent --coverage",
29
29
  "prepack": "pnpm test"
30
30
  },
31
31
  "dependencies": {
32
- "@logto/core-kit": "1.0.0-beta.16",
33
- "@logto/js": "^1.0.0-beta.9",
32
+ "@logto/js": "^1.0.0",
34
33
  "@silverhand/essentials": "^1.2.1",
35
34
  "camelcase-keys": "^7.0.1",
36
35
  "jose": "^4.3.8",
@@ -39,26 +38,26 @@
39
38
  },
40
39
  "devDependencies": {
41
40
  "@jest/types": "^27.5.1",
42
- "@parcel/core": "^2.7.0",
43
- "@parcel/packager-ts": "^2.7.0",
44
- "@parcel/transformer-typescript-types": "^2.7.0",
45
- "@silverhand/eslint-config": "^1.0.0",
41
+ "@parcel/core": "^2.8.3",
42
+ "@parcel/packager-ts": "^2.8.3",
43
+ "@parcel/transformer-typescript-types": "^2.8.3",
44
+ "@silverhand/eslint-config": "^2.0.0",
46
45
  "@silverhand/ts-config": "^1.0.0",
47
46
  "@types/jest": "^27.4.1",
48
47
  "@types/lodash.get": "^4.4.6",
49
48
  "@types/lodash.once": "^4.1.7",
50
- "@types/node": "^17.0.19",
49
+ "@types/node": "^18.0.0",
51
50
  "eslint": "^8.23.0",
52
51
  "jest": "^27.5.1",
53
52
  "jest-matcher-specific-error": "^1.0.0",
54
53
  "lint-staged": "^13.0.0",
55
54
  "nock": "^13.1.3",
56
- "parcel": "^2.7.0",
55
+ "parcel": "^2.8.3",
57
56
  "prettier": "^2.7.1",
58
57
  "text-encoder": "^0.0.4",
59
58
  "ts-jest": "^27.0.4",
60
59
  "type-fest": "^3.0.0",
61
- "typescript": "4.7.4"
60
+ "typescript": "4.9.5"
62
61
  },
63
62
  "eslintConfig": {
64
63
  "extends": "@silverhand"
@@ -67,5 +66,5 @@
67
66
  "publishConfig": {
68
67
  "access": "public"
69
68
  },
70
- "gitHead": "196ece6cad697ec93f53230cd165fedc7aa5d825"
69
+ "gitHead": "fff27b23a74d5bd3a46fc83fbbc2901b6e054c72"
71
70
  }
package/lib/module.js.map DELETED
@@ -1 +0,0 @@
1
- {"mappings":"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","sources":["packages/client/src/index.ts","packages/client/src/errors.ts","packages/client/src/types/index.ts","packages/client/src/utils/index.ts","packages/client/src/utils/requester.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { ReservedScope } from '@logto/core-kit';\nimport {\n CodeTokenResponse,\n decodeIdToken,\n fetchOidcConfig,\n fetchTokenByAuthorizationCode,\n fetchTokenByRefreshToken,\n fetchUserInfo,\n generateSignInUri,\n generateSignOutUri,\n IdTokenClaims,\n Prompt,\n revoke,\n UserInfoResponse,\n verifyAndParseCodeFromCallbackUri,\n verifyIdToken,\n withDefaultScopes,\n} from '@logto/js';\nimport { Nullable } from '@silverhand/essentials';\nimport { createRemoteJWKSet } from 'jose';\nimport once from 'lodash.once';\n\nimport { ClientAdapter } from './adapter';\nimport { LogtoClientError } from './errors';\nimport {\n AccessToken,\n isLogtoAccessTokenMap,\n isLogtoSignInSessionItem,\n LogtoConfig,\n LogtoSignInSessionItem,\n} from './types';\nimport { buildAccessTokenKey, getDiscoveryEndpoint } from './utils';\n\nexport type { IdTokenClaims, LogtoErrorCode, UserInfoResponse } from '@logto/js';\nexport { LogtoError, OidcError, Prompt, LogtoRequestError } from '@logto/js';\nexport * from './errors';\nexport type { Storage, StorageKey, ClientAdapter } from './adapter';\nexport { createRequester } from './utils';\nexport * from './types';\nexport { ReservedScope, UserScope } from '@logto/core-kit';\n\nexport default class LogtoClient {\n protected readonly logtoConfig: LogtoConfig;\n protected readonly getOidcConfig = once(this._getOidcConfig);\n protected readonly getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);\n protected readonly adapter: ClientAdapter;\n protected readonly accessTokenMap = new Map<string, AccessToken>();\n\n private readonly getAccessTokenPromiseMap = new Map<string, Promise<string>>();\n\n constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter) {\n this.logtoConfig = {\n ...logtoConfig,\n prompt: logtoConfig.prompt ?? Prompt.Consent,\n scopes: withDefaultScopes(logtoConfig.scopes).split(' '),\n };\n this.adapter = adapter;\n\n void this.loadAccessTokenMap();\n }\n\n async isAuthenticated() {\n return Boolean(await this.getIdToken());\n }\n\n async getRefreshToken() {\n return this.adapter.storage.getItem('refreshToken');\n }\n\n async getIdToken() {\n return this.adapter.storage.getItem('idToken');\n }\n\n // eslint-disable-next-line complexity\n async getAccessToken(resource?: string): Promise<string> {\n if (!(await this.getIdToken())) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const accessTokenKey = buildAccessTokenKey(resource);\n const accessToken = this.accessTokenMap.get(accessTokenKey);\n\n if (accessToken && accessToken.expiresAt > Date.now() / 1000) {\n return accessToken.token;\n }\n\n // Since the access token has expired, delete it from the map.\n if (accessToken) {\n this.accessTokenMap.delete(accessTokenKey);\n }\n\n /**\n * Need to fetch a new access token using refresh token.\n * Reuse the cached promise if exists.\n */\n const cachedPromise = this.getAccessTokenPromiseMap.get(accessTokenKey);\n\n if (cachedPromise) {\n return cachedPromise;\n }\n\n /**\n * Create a new promise and cache in map to avoid race condition.\n * Since we enable \"refresh token rotation\" by default,\n * it will be problematic when calling multiple `getAccessToken()` closely.\n */\n const promise = this.getAccessTokenByRefreshToken(resource);\n this.getAccessTokenPromiseMap.set(accessTokenKey, promise);\n\n const token = await promise;\n this.getAccessTokenPromiseMap.delete(accessTokenKey);\n\n return token;\n }\n\n async getIdTokenClaims(): Promise<IdTokenClaims> {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n return decodeIdToken(idToken);\n }\n\n async fetchUserInfo(): Promise<UserInfoResponse> {\n const { userinfoEndpoint } = await this.getOidcConfig();\n const accessToken = await this.getAccessToken();\n\n if (!accessToken) {\n throw new LogtoClientError('fetch_user_info_failed');\n }\n\n return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);\n }\n\n async signIn(redirectUri: string) {\n const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;\n const { authorizationEndpoint } = await this.getOidcConfig();\n const codeVerifier = this.adapter.generateCodeVerifier();\n const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);\n const state = this.adapter.generateState();\n\n const signInUri = generateSignInUri({\n authorizationEndpoint,\n clientId,\n redirectUri,\n codeChallenge,\n state,\n scopes,\n resources,\n prompt,\n });\n\n await this.setSignInSession({ redirectUri, codeVerifier, state });\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(signInUri);\n }\n\n async isSignInRedirected(url: string): Promise<boolean> {\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n return false;\n }\n const { redirectUri } = signInSession;\n const { origin, pathname } = new URL(url);\n\n return `${origin}${pathname}` === redirectUri;\n }\n\n async handleSignInCallback(callbackUri: string) {\n const { logtoConfig, adapter } = this;\n const { requester } = adapter;\n const signInSession = await this.getSignInSession();\n\n if (!signInSession) {\n throw new LogtoClientError('sign_in_session.not_found');\n }\n\n const { redirectUri, state, codeVerifier } = signInSession;\n const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);\n\n const { appId: clientId } = logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const codeTokenResponse = await fetchTokenByAuthorizationCode(\n {\n clientId,\n tokenEndpoint,\n redirectUri,\n codeVerifier,\n code,\n },\n requester\n );\n\n await this.verifyIdToken(codeTokenResponse.idToken);\n await this.saveCodeToken(codeTokenResponse);\n await this.setSignInSession(null);\n }\n\n async signOut(postLogoutRedirectUri?: string) {\n const idToken = await this.getIdToken();\n\n if (!idToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n const { appId: clientId } = this.logtoConfig;\n const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig();\n const refreshToken = await this.getRefreshToken();\n\n if (refreshToken) {\n try {\n await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);\n } catch {\n // Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed\n }\n }\n\n const url = generateSignOutUri({\n endSessionEndpoint,\n postLogoutRedirectUri,\n idToken,\n });\n\n this.accessTokenMap.clear();\n await this.setRefreshToken(null);\n await this.setIdToken(null);\n\n this.adapter.navigate(url);\n }\n\n protected async getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>> {\n const jsonItem = await this.adapter.storage.getItem('signInSession');\n\n if (!jsonItem) {\n return null;\n }\n\n const item: unknown = JSON.parse(jsonItem);\n\n if (!isLogtoSignInSessionItem(item)) {\n throw new LogtoClientError('sign_in_session.invalid');\n }\n\n return item;\n }\n\n protected async setSignInSession(logtoSignInSessionItem: Nullable<LogtoSignInSessionItem>) {\n if (!logtoSignInSessionItem) {\n await this.adapter.storage.removeItem('signInSession');\n\n return;\n }\n\n const jsonItem = JSON.stringify(logtoSignInSessionItem);\n await this.adapter.storage.setItem('signInSession', jsonItem);\n }\n\n private async setIdToken(idToken: Nullable<string>) {\n if (!idToken) {\n await this.adapter.storage.removeItem('idToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('idToken', idToken);\n }\n\n private async setRefreshToken(refreshToken: Nullable<string>) {\n if (!refreshToken) {\n await this.adapter.storage.removeItem('refreshToken');\n\n return;\n }\n\n await this.adapter.storage.setItem('refreshToken', refreshToken);\n }\n\n private async getAccessTokenByRefreshToken(resource?: string): Promise<string> {\n const currentRefreshToken = await this.getRefreshToken();\n\n if (!currentRefreshToken) {\n throw new LogtoClientError('not_authenticated');\n }\n\n try {\n const accessTokenKey = buildAccessTokenKey(resource);\n const { appId: clientId } = this.logtoConfig;\n const { tokenEndpoint } = await this.getOidcConfig();\n const { accessToken, refreshToken, idToken, scope, expiresIn } =\n await fetchTokenByRefreshToken(\n {\n clientId,\n tokenEndpoint,\n refreshToken: currentRefreshToken,\n resource,\n scopes: resource ? [ReservedScope.OfflineAccess] : undefined, // Force remove openid scope from the request\n },\n this.adapter.requester\n );\n\n this.accessTokenMap.set(accessTokenKey, {\n token: accessToken,\n scope,\n expiresAt: Math.round(Date.now() / 1000) + expiresIn,\n });\n\n await this.saveAccessTokenMap();\n await this.setRefreshToken(refreshToken);\n\n if (idToken) {\n await this.verifyIdToken(idToken);\n await this.setIdToken(idToken);\n }\n\n return accessToken;\n } catch (error: unknown) {\n throw new LogtoClientError('get_access_token_by_refresh_token_failed', error);\n }\n }\n\n private async _getOidcConfig() {\n const { endpoint } = this.logtoConfig;\n const discoveryEndpoint = getDiscoveryEndpoint(endpoint);\n\n return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);\n }\n\n private async _getJwtVerifyGetKey() {\n const { jwksUri } = await this.getOidcConfig();\n\n return createRemoteJWKSet(new URL(jwksUri));\n }\n\n private async verifyIdToken(idToken: string) {\n const { appId } = this.logtoConfig;\n const { issuer } = await this.getOidcConfig();\n const jwtVerifyGetKey = await this.getJwtVerifyGetKey();\n\n try {\n await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);\n } catch (error: unknown) {\n throw new LogtoClientError('invalid_id_token', error);\n }\n }\n\n private async saveCodeToken({\n refreshToken,\n idToken,\n scope,\n accessToken,\n expiresIn,\n }: CodeTokenResponse) {\n await this.setRefreshToken(refreshToken ?? null);\n await this.setIdToken(idToken);\n\n // NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)\n const accessTokenKey = buildAccessTokenKey();\n const expiresAt = Date.now() / 1000 + expiresIn;\n this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });\n await this.saveAccessTokenMap();\n }\n\n private async saveAccessTokenMap() {\n const data: Record<string, AccessToken> = {};\n\n for (const [key, accessToken] of this.accessTokenMap.entries()) {\n // eslint-disable-next-line @silverhand/fp/no-mutation\n data[key] = accessToken;\n }\n\n await this.adapter.storage.setItem('accessToken', JSON.stringify(data));\n }\n\n private async loadAccessTokenMap() {\n const raw = await this.adapter.storage.getItem('accessToken');\n\n if (!raw) {\n return;\n }\n\n try {\n const json: unknown = JSON.parse(raw);\n\n if (!isLogtoAccessTokenMap(json)) {\n return;\n }\n this.accessTokenMap.clear();\n\n for (const [key, accessToken] of Object.entries(json)) {\n this.accessTokenMap.set(key, accessToken);\n }\n } catch {}\n }\n}\n/* eslint-enable max-lines */\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 fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',\n invalid_id_token: 'Invalid id token.',\n});\n\nexport type LogtoClientErrorCode = NormalizeKeyPaths<typeof logtoClientErrorCodes>;\n\nconst getMessageByErrorCode = (errorCode: LogtoClientErrorCode): string => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const message = get(logtoClientErrorCodes, errorCode);\n\n if (typeof message === 'string') {\n return message;\n }\n\n return errorCode;\n};\n\nexport class LogtoClientError extends Error {\n code: LogtoClientErrorCode;\n data: unknown;\n\n constructor(code: LogtoClientErrorCode, data?: unknown) {\n super(getMessageByErrorCode(code));\n this.code = code;\n this.data = data;\n }\n}\n","import { isArbitraryObject, Prompt } from '@logto/js';\n\nexport type LogtoConfig = {\n endpoint: string;\n appId: string;\n appSecret?: string;\n scopes?: string[];\n resources?: string[];\n prompt?: Prompt;\n};\n\nexport type AccessToken = {\n token: string;\n scope: string;\n expiresAt: number;\n};\n\nexport const isLogtoSignInSessionItem = (data: unknown): data is LogtoSignInSessionItem => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');\n};\n\nexport const isLogtoAccessTokenMap = (data: unknown): data is Record<string, AccessToken> => {\n if (!isArbitraryObject(data)) {\n return false;\n }\n\n return Object.values(data).every((value) => {\n if (!isArbitraryObject(value)) {\n return false;\n }\n\n return (\n typeof value.token === 'string' &&\n typeof value.scope === 'string' &&\n typeof value.expiresAt === 'number'\n );\n });\n};\n\nexport type LogtoSignInSessionItem = {\n redirectUri: string;\n codeVerifier: string;\n state: string;\n};\n","import { discoveryPath } from '@logto/js';\n\nexport * from './requester';\n\nexport const buildAccessTokenKey = (resource = '', scopes: string[] = []): string =>\n `${scopes.slice().sort().join(' ')}@${resource}`;\n\nexport const getDiscoveryEndpoint = (endpoint: string): string =>\n new URL(discoveryPath, endpoint).toString();\n","import { LogtoError, LogtoRequestError, isLogtoRequestError, Requester } from '@logto/js';\n\nexport const createRequester = (fetchFunction: typeof fetch): Requester => {\n return async <T>(...args: Parameters<typeof fetch>): Promise<T> => {\n const response = await fetchFunction(...args);\n\n if (!response.ok) {\n const responseJson = await response.json();\n\n if (!isLogtoRequestError(responseJson)) {\n throw new LogtoError('unexpected_response_error', responseJson);\n }\n\n // Expected request error from server\n const { code, message } = responseJson;\n throw new LogtoRequestError(code, message);\n }\n\n return response.json();\n };\n};\n"],"names":[],"version":3,"file":"module.js.map"}