@logto/client
Advanced tools
Comparing version 2.2.1 to 2.2.2
@@ -25,2 +25,7 @@ import type { Requester } from '@logto/js'; | ||
} | ||
/** | ||
* The storage object that allows the client to persist data. | ||
* | ||
* It's compatible with the `localStorage` API. | ||
*/ | ||
export type Storage<Keys extends string> = { | ||
@@ -32,3 +37,8 @@ getItem(key: Keys): Promise<Nullable<string>>; | ||
export type InferStorageKey<S> = S extends Storage<infer Key> ? Key : never; | ||
export type Navigate = (url: string) => void; | ||
/** The navigation function that redirects the user to the specified URL. */ | ||
export type Navigate = (url: string) => void | Promise<void>; | ||
/** | ||
* The adapter object that allows the customizations of the client behavior | ||
* for different environments. | ||
*/ | ||
export type ClientAdapter = { | ||
@@ -44,5 +54,24 @@ requester: Requester; | ||
navigate: Navigate; | ||
/** | ||
* The function that generates a random state string. | ||
* | ||
* @returns The state string. | ||
*/ | ||
generateState: () => string; | ||
/** | ||
* The function that generates a random code verifier string for PKCE. | ||
* | ||
* @see {@link https://www.rfc-editor.org/rfc/rfc7636.html| RFC 7636} | ||
* @returns The code verifier string. | ||
*/ | ||
generateCodeVerifier: () => string; | ||
/** | ||
* The function that generates a code challenge string based on the code verifier | ||
* for PKCE. | ||
* | ||
* @see {@link https://www.rfc-editor.org/rfc/rfc7636.html| RFC 7636} | ||
* @param codeVerifier The code verifier string. | ||
* @returns The code challenge string. | ||
*/ | ||
generateCodeChallenge: (codeVerifier: string) => Promise<string>; | ||
}; |
@@ -6,5 +6,7 @@ declare const logtoClientErrorCodes: Readonly<{ | ||
fetch_user_info_failed: "Unable to fetch user info. The access token may be invalid."; | ||
user_cancelled: "The user cancelled the action."; | ||
}>; | ||
export type LogtoClientErrorCode = keyof typeof logtoClientErrorCodes; | ||
export declare class LogtoClientError extends Error { | ||
name: string; | ||
code: LogtoClientErrorCode; | ||
@@ -11,0 +13,0 @@ data: unknown; |
@@ -6,2 +6,3 @@ const logtoClientErrorCodes = Object.freeze({ | ||
fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.', | ||
user_cancelled: 'The user cancelled the action.', | ||
}); | ||
@@ -11,2 +12,3 @@ class LogtoClientError extends Error { | ||
super(logtoClientErrorCodes[code]); | ||
this.name = 'LogtoClientError'; | ||
this.code = code; | ||
@@ -13,0 +15,0 @@ this.data = data; |
@@ -13,2 +13,9 @@ import { type IdTokenClaims, type UserInfoResponse, type InteractionMode, type AccessTokenClaims } from '@logto/js'; | ||
export * from './types/index.js'; | ||
/** | ||
* The Logto base client class that provides the essential methods for | ||
* interacting with the Logto server. | ||
* | ||
* It also provides an adapter object that allows the customizations of the | ||
* client behavior for different environments. | ||
*/ | ||
export default class LogtoClient { | ||
@@ -30,12 +37,96 @@ #private; | ||
constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter); | ||
/** | ||
* Check if the user is authenticated by checking if the ID token exists. | ||
*/ | ||
isAuthenticated(): Promise<boolean>; | ||
/** | ||
* Get the Refresh Token from the storage. | ||
*/ | ||
getRefreshToken(): Promise<Nullable<string>>; | ||
/** | ||
* Get the ID Token from the storage. If you want to get the ID Token claims, | ||
* use {@link getIdTokenClaims} instead. | ||
*/ | ||
getIdToken(): Promise<Nullable<string>>; | ||
/** | ||
* Get the Access Token from the storage. If the Access Token has expired, it | ||
* will try to fetch a new one using the Refresh Token. | ||
* | ||
* If you want to get the Access Token claims, use {@link getAccessTokenClaims} instead. | ||
* | ||
* @param resource The resource that the Access Token is granted for. If not | ||
* specified, the Access Token will be used for OpenID Connect or the default | ||
* resource, as specified in the Logto Console. | ||
* @returns The Access Token string. | ||
* @throws LogtoClientError if the user is not authenticated. | ||
*/ | ||
getAccessToken(resource?: string): Promise<string>; | ||
/** | ||
* Get the ID Token claims. | ||
*/ | ||
getIdTokenClaims(): Promise<IdTokenClaims>; | ||
/** | ||
* Get the Access Token claims for the specified resource. | ||
* | ||
* @param resource The resource that the Access Token is granted for. If not | ||
* specified, the Access Token will be used for OpenID Connect or the default | ||
* resource, as specified in the Logto Console. | ||
*/ | ||
getAccessTokenClaims(resource?: string): Promise<AccessTokenClaims>; | ||
/** | ||
* Get the user information from the Userinfo Endpoint. | ||
* | ||
* Note the Userinfo Endpoint will return more claims than the ID Token. See | ||
* {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#fetch-user-information | Fetch user information} | ||
* for more information. | ||
* | ||
* @returns The user information. | ||
* @throws LogtoClientError if the user is not authenticated. | ||
*/ | ||
fetchUserInfo(): Promise<UserInfoResponse>; | ||
/** | ||
* Start the sign-in flow with the specified redirect URI. The URI must be | ||
* registered in the Logto Console. | ||
* | ||
* The user will be redirected to that URI after the sign-in flow is completed, | ||
* and the client will be able to get the authorization code from the URI. | ||
* To fetch the tokens from the authorization code, use {@link handleSignInCallback} | ||
* after the user is redirected in the callback URI. | ||
* | ||
* @param redirectUri The redirect URI that the user will be redirected to after the sign-in flow is completed. | ||
* @param interactionMode The interaction mode to be used for the authorization request. Note it's not | ||
* a part of the OIDC standard, but a Logto-specific extension. Defaults to `signIn`. | ||
* | ||
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#sign-in | Sign in} for more information. | ||
* @see {@link InteractionMode} | ||
*/ | ||
signIn(redirectUri: string, interactionMode?: InteractionMode): Promise<void>; | ||
/** | ||
* Check if the user is redirected from the sign-in page by checking if the | ||
* current URL matches the redirect URI in the sign-in session. | ||
* | ||
* If there's no sign-in session, it will return `false`. | ||
* | ||
* @param url The current URL. | ||
*/ | ||
isSignInRedirected(url: string): Promise<boolean>; | ||
/** | ||
* Handle the sign-in callback by parsing the authorization code from the | ||
* callback URI and exchanging it for the tokens. | ||
* | ||
* @param callbackUri The callback URI that the user is redirected to after the sign-in flow is completed. | ||
* This URI must match the redirect URI specified in {@link signIn}. | ||
* @throws LogtoClientError if the sign-in session is not found. | ||
*/ | ||
handleSignInCallback(callbackUri: string): Promise<void>; | ||
/** | ||
* Start the sign-out flow with the specified redirect URI. The URI must be | ||
* registered in the Logto Console. | ||
* | ||
* It will also revoke all the tokens and clean up the storage. | ||
* | ||
* The user will be redirected that URI after the sign-out flow is completed. | ||
* If the `postLogoutRedirectUri` is not specified, the user will be redirected | ||
* to a default page. | ||
*/ | ||
signOut(postLogoutRedirectUri?: string): Promise<void>; | ||
@@ -42,0 +133,0 @@ protected getSignInSession(): Promise<Nullable<LogtoSignInSessionItem>>; |
111
lib/index.js
@@ -14,2 +14,9 @@ import { Prompt, withDefaultScopes, decodeIdToken, decodeAccessToken, fetchUserInfo, generateSignInUri, verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode, revoke, generateSignOutUri, fetchTokenByRefreshToken, verifyIdToken, fetchOidcConfig } from '@logto/js'; | ||
/** | ||
* The Logto base client class that provides the essential methods for | ||
* interacting with the Logto server. | ||
* | ||
* It also provides an adapter object that allows the customizations of the | ||
* client behavior for different environments. | ||
*/ | ||
class LogtoClient { | ||
@@ -28,11 +35,33 @@ constructor(logtoConfig, adapter) { | ||
} | ||
/** | ||
* Check if the user is authenticated by checking if the ID token exists. | ||
*/ | ||
async isAuthenticated() { | ||
return Boolean(await this.getIdToken()); | ||
} | ||
/** | ||
* Get the Refresh Token from the storage. | ||
*/ | ||
async getRefreshToken() { | ||
return this.adapter.storage.getItem('refreshToken'); | ||
} | ||
/** | ||
* Get the ID Token from the storage. If you want to get the ID Token claims, | ||
* use {@link getIdTokenClaims} instead. | ||
*/ | ||
async getIdToken() { | ||
return this.adapter.storage.getItem('idToken'); | ||
} | ||
/** | ||
* Get the Access Token from the storage. If the Access Token has expired, it | ||
* will try to fetch a new one using the Refresh Token. | ||
* | ||
* If you want to get the Access Token claims, use {@link getAccessTokenClaims} instead. | ||
* | ||
* @param resource The resource that the Access Token is granted for. If not | ||
* specified, the Access Token will be used for OpenID Connect or the default | ||
* resource, as specified in the Logto Console. | ||
* @returns The Access Token string. | ||
* @throws LogtoClientError if the user is not authenticated. | ||
*/ | ||
async getAccessToken(resource) { | ||
@@ -56,2 +85,5 @@ if (!(await this.getIdToken())) { | ||
} | ||
/** | ||
* Get the ID Token claims. | ||
*/ | ||
async getIdTokenClaims() { | ||
@@ -64,2 +96,9 @@ const idToken = await this.getIdToken(); | ||
} | ||
/** | ||
* Get the Access Token claims for the specified resource. | ||
* | ||
* @param resource The resource that the Access Token is granted for. If not | ||
* specified, the Access Token will be used for OpenID Connect or the default | ||
* resource, as specified in the Logto Console. | ||
*/ | ||
async getAccessTokenClaims(resource) { | ||
@@ -69,2 +108,12 @@ const accessToken = await this.getAccessToken(resource); | ||
} | ||
/** | ||
* Get the user information from the Userinfo Endpoint. | ||
* | ||
* Note the Userinfo Endpoint will return more claims than the ID Token. See | ||
* {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#fetch-user-information | Fetch user information} | ||
* for more information. | ||
* | ||
* @returns The user information. | ||
* @throws LogtoClientError if the user is not authenticated. | ||
*/ | ||
async fetchUserInfo() { | ||
@@ -78,2 +127,18 @@ const { userinfoEndpoint } = await this.getOidcConfig(); | ||
} | ||
/** | ||
* Start the sign-in flow with the specified redirect URI. The URI must be | ||
* registered in the Logto Console. | ||
* | ||
* The user will be redirected to that URI after the sign-in flow is completed, | ||
* and the client will be able to get the authorization code from the URI. | ||
* To fetch the tokens from the authorization code, use {@link handleSignInCallback} | ||
* after the user is redirected in the callback URI. | ||
* | ||
* @param redirectUri The redirect URI that the user will be redirected to after the sign-in flow is completed. | ||
* @param interactionMode The interaction mode to be used for the authorization request. Note it's not | ||
* a part of the OIDC standard, but a Logto-specific extension. Defaults to `signIn`. | ||
* | ||
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#sign-in | Sign in} for more information. | ||
* @see {@link InteractionMode} | ||
*/ | ||
async signIn(redirectUri, interactionMode) { | ||
@@ -96,7 +161,17 @@ const { appId: clientId, prompt, resources, scopes } = this.logtoConfig; | ||
}); | ||
await this.setSignInSession({ redirectUri, codeVerifier, state }); | ||
await this.setRefreshToken(null); | ||
await this.setIdToken(null); | ||
this.adapter.navigate(signInUri); | ||
await Promise.all([ | ||
this.setSignInSession({ redirectUri, codeVerifier, state }), | ||
this.setRefreshToken(null), | ||
this.setIdToken(null), | ||
]); | ||
await this.adapter.navigate(signInUri); | ||
} | ||
/** | ||
* Check if the user is redirected from the sign-in page by checking if the | ||
* current URL matches the redirect URI in the sign-in session. | ||
* | ||
* If there's no sign-in session, it will return `false`. | ||
* | ||
* @param url The current URL. | ||
*/ | ||
async isSignInRedirected(url) { | ||
@@ -111,2 +186,10 @@ const signInSession = await this.getSignInSession(); | ||
} | ||
/** | ||
* Handle the sign-in callback by parsing the authorization code from the | ||
* callback URI and exchanging it for the tokens. | ||
* | ||
* @param callbackUri The callback URI that the user is redirected to after the sign-in flow is completed. | ||
* This URI must match the redirect URI specified in {@link signIn}. | ||
* @throws LogtoClientError if the sign-in session is not found. | ||
*/ | ||
async handleSignInCallback(callbackUri) { | ||
@@ -147,2 +230,12 @@ const { requester } = this.adapter; | ||
} | ||
/** | ||
* Start the sign-out flow with the specified redirect URI. The URI must be | ||
* registered in the Logto Console. | ||
* | ||
* It will also revoke all the tokens and clean up the storage. | ||
* | ||
* The user will be redirected that URI after the sign-out flow is completed. | ||
* If the `postLogoutRedirectUri` is not specified, the user will be redirected | ||
* to a default page. | ||
*/ | ||
async signOut(postLogoutRedirectUri) { | ||
@@ -166,6 +259,8 @@ const { appId: clientId } = this.logtoConfig; | ||
this.accessTokenMap.clear(); | ||
await this.setRefreshToken(null); | ||
await this.setIdToken(null); | ||
await this.adapter.storage.removeItem('accessToken'); | ||
this.adapter.navigate(url); | ||
await Promise.all([ | ||
this.setRefreshToken(null), | ||
this.setIdToken(null), | ||
this.adapter.storage.removeItem('accessToken'), | ||
]); | ||
await this.adapter.navigate(url); | ||
} | ||
@@ -172,0 +267,0 @@ async getSignInSession() { |
import type { Prompt } from '@logto/js'; | ||
/** The configuration object for the Logto client. */ | ||
export type LogtoConfig = { | ||
/** | ||
* The endpoint for the Logto server, you can get it from the integration guide | ||
* or the team settings page of the Logto Console. | ||
* | ||
* @example https://foo.logto.app | ||
*/ | ||
endpoint: string; | ||
/** | ||
* The client ID of your application, you can get it from the integration guide | ||
* or the application details page of the Logto Console. | ||
*/ | ||
appId: string; | ||
/** | ||
* The client secret of your application, you can get it from the application | ||
* details page of the Logto Console. | ||
*/ | ||
appSecret?: string; | ||
/** | ||
* The scopes (permissions) that your application needs to access. | ||
* Scopes that will be added by default: `openid`, `offline_access` and `profile`. | ||
* | ||
* If resources are specified, scopes will be applied to every resource. | ||
* | ||
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#fetch-user-information | Fetch user information} | ||
* for more information of available scopes for user information. | ||
*/ | ||
scopes?: string[]; | ||
/** | ||
* The API resources that your application needs to access. You can specify | ||
* multiple resources by providing an array of strings. | ||
* | ||
* @see {@link https://docs.logto.io/docs/recipes/rbac/ | RBAC} to learn more about how to use role-based access control (RBAC) to protect API resources. | ||
*/ | ||
resources?: string[]; | ||
/** | ||
* The prompt parameter to be used for the authorization request. | ||
*/ | ||
prompt?: Prompt; | ||
}; | ||
export type AccessToken = { | ||
/** The access token string. */ | ||
token: string; | ||
/** The scopes that the access token is granted for. */ | ||
scope: string; | ||
/** The timestamp of the access token expiration. */ | ||
expiresAt: number; | ||
@@ -14,0 +50,0 @@ }; |
import type { Requester } from '@logto/js'; | ||
/** | ||
* A factory function that creates a requester by accepting a `fetch`-like function. | ||
* | ||
* @param fetchFunction A `fetch`-like function. | ||
* @returns A requester function. | ||
* @see {@link Requester} | ||
*/ | ||
export declare const createRequester: (fetchFunction: typeof fetch) => Requester; |
import { isLogtoRequestError, LogtoError, LogtoRequestError } from '@logto/js'; | ||
/** | ||
* A factory function that creates a requester by accepting a `fetch`-like function. | ||
* | ||
* @param fetchFunction A `fetch`-like function. | ||
* @returns A requester function. | ||
* @see {@link Requester} | ||
*/ | ||
const createRequester = (fetchFunction) => { | ||
@@ -4,0 +11,0 @@ return async (...args) => { |
{ | ||
"name": "@logto/client", | ||
"version": "2.2.1", | ||
"version": "2.2.2", | ||
"type": "module", | ||
@@ -24,3 +24,3 @@ "main": "./lib/index.cjs", | ||
"dependencies": { | ||
"@logto/js": "^2.1.0", | ||
"@logto/js": "^2.1.2", | ||
"@silverhand/essentials": "^2.6.2", | ||
@@ -27,0 +27,0 @@ "camelcase-keys": "^7.0.1", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
88136
2067
Updated@logto/js@^2.1.2