Crafting a web SDK for Logto in minutes
Palomino
Posted on June 17, 2024
Learn how to create a custom SDK for Logto using @logto/browser
.
Logto, an open-source auth platform, offers a plethora of official SDKs designed to simplify integration for various frameworks and platforms. However, there are still many platforms that do not have official SDKs.
To bridge this gap, Logto provides the fundamental package @logto/browser
, designed to help developers craft custom SDKs tailored to specific requirements. This package implements the core functionalities of Logto, detached from any specific framework or platform, as long as it supports JavaScript and runs in a browser environment.
In this guide, we will walk you through the steps to create a React SDK using @logto/browser, this SDK will implement the sign-in flow. You can follow the same steps to create an SDK for any other JavaScript-based platform that running in browser.
The sign-in flow
Before we start, let's understand the sign-in flow in Logto. The sign-in flow consists of the following steps:
- Redirect to Logto: The user is redirected to the Logto sign-in page.
- Authenticate: The user inputs their credentials and authenticates with Logto.
- Redirect back to your app: After successful authentication, the user is redirected back to your app with an auth code.
- Code exchange: Your app exchanges the auth code for tokens.
Brief introduction of @logto/browser
The @logto/browser
package exposes a LogtoClient
class that provides the core functionalities of Logto, including methods for sign-in flow:
-
signIn()
: Generates the OIDC auth URL, and redirects to it. -
handleSignInCallback()
: Check and parse the callback URL and extract the auth code, then exchange the code for tokens by calling token endpoint. -
isAuthenticated()
: Check if the user is authenticated.
Crafting the React SDK
In the SDK, we will provide 2 hooks: useLogto
and useHandleSignInCallback
, and along with a LogtoProvider
component:
-
useLogto
: A hook that provides thesignIn
method to trigger the sign-in flow, and theisAuthenticated
state to check if the user is authenticated. -
useHandleSignInCallback
: A hook that handles the callback URL and exchanges the auth code for tokens, complete the sign-in flow.
To use the SDK, you can simply wrap your app with the LogtoProvider
component, and use the hooks to check auth state, sign-in and handle the callback.
Step 1: Install the package
First, install the @logto/browser
package using npm or other package managers:
npm install @logto/browser
Step 2: Define the context of React
Define the context of the provider, containing 3 parts:
- The underlying
LogtoClient
instance which will be initialized in the provider, and used in the hooks. - The authentication state.
- The method to set the authentication state.
Create a new file context.tsx
and write the following code:
import type LogtoClient from '@logto/browser';
import { createContext } from 'react';
export type LogtoContextProps = {
/** The underlying LogtoClient instance (from `@logto/browser`). */
logtoClient?: LogtoClient;
/** Whether the user is authenticated or not. */
isAuthenticated: boolean;
/** Sets the authentication state. */
setIsAuthenticated: React.Dispatch<React.SetStateAction<boolean>>;
};
export const throwContextError = (): never => {
throw new Error('Must be used inside <LogtoProvider> context.');
};
/**
* The context for the LogtoProvider.
*
* @remarks
* Instead of using this context directly, in most cases you should use the `useLogto` hook.
*/
export const LogtoContext = createContext<LogtoContextProps>({
logtoClient: undefined,
isAuthenticated: false,
setIsAuthenticated: throwContextError,
});
Step 3: Implement the provider
With the context ready, let's implement the provider. The provider will initialize the LogtoClient
instance, check if the user is authenticated, and provide the context to its children.
Create a new file provider.tsx
:
import LogtoClient, { type LogtoConfig } from '@logto/browser';
import { type ReactNode, useEffect, useMemo, useState, useCallback } from 'react';
import { LogtoContext } from './context.js';
export type LogtoProviderProps = {
config: LogtoConfig;
children?: ReactNode;
};
export const LogtoProvider = ({ config, children }: LogtoProviderProps) => {
const [loadingCount, setLoadingCount] = useState(1);
const memoizedLogtoClient = useMemo(() => ({ logtoClient: new LogtoClient(config) }), [config]);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
(async () => {
const isAuthenticated = await memoizedLogtoClient.logtoClient.isAuthenticated();
setIsAuthenticated(isAuthenticated);
})();
}, [memoizedLogtoClient]);
const memoizedContextValue = useMemo(
() => ({
...memoizedLogtoClient,
isAuthenticated,
setIsAuthenticated,
}),
[memoizedLogtoClient, isAuthenticated, setIsAuthenticated]
);
return <LogtoContext.Provider value={memoizedContextValue}>{children}</LogtoContext.Provider>;
};
Step 4: Implement the hooks
Now, let's implement the hooks.
-
useLogto
: In this hook, we use the context to get theLogtoClient
instance, and provide thesignIn
method andisAuthenticated
state. You can continue to add more methods to this hook. -
useHandleSignInCallback
: This hook will read the callback URL from the browser, extract the auth code, and exchange it for tokens. It will also set the authentication state totrue
after the user is authenticated.
Create a new file hooks.ts
and write the following code:
import type LogtoClient from '@logto/browser';
import { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
import { LogtoContext, throwContextError } from './context.js';
type Logto = {
isAuthenticated: boolean;
} & Pick<LogtoClient, 'signIn'>;
const useHandleSignInCallback = (callback?: () => void) => {
const { logtoClient, isAuthenticated, setIsAuthenticated } = useContext(LogtoContext);
useEffect(() => {
if (!logtoClient) {
return;
}
(async () => {
if (!isAuthenticated) {
await logtoClient.handleSignInCallback(window.location.href);
setIsAuthenticated(true);
callbackRef.current?.();
}
})();
}, [isAuthenticated, logtoClient, setIsAuthenticated]);
return {
isAuthenticated,
};
};
const useLogto = (): Logto => {
const { logtoClient, isAuthenticated } = useContext(LogtoContext);
const client = logtoClient ?? throwContextError();
const methods = useMemo(
() => ({
signIn: client.signIn,
// other methods
}),
[client, proxy]
);
return {
isAuthenticated,
...methods,
};
};
export { useLogto, useHandleSignInCallback };
Checkpoint: using the SDK
Now, you have crafted the React SDK for Logto. You can use it in your app by wrapping the app with the LogtoProvider
component, and using the hooks to check the auth state, sign in, and handle the callback. You can check the official React sample project here.
Conclusion
In this guide, we have walked you through the steps to create a React SDK for Logto implementing the basic auth flow. The SDK provided here is a basic example. You can extend it by adding more methods and functionalities to meet your app's needs.
You can follow the same steps to create an SDK for any other JavaScript-based platform that runs in a browser.
Resources:
Posted on June 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.