6.6 KiB
New Authentication Provider Guide
LobeChat uses Auth.js v5 as the external authentication service. Auth.js is an open-source authentication library that provides a simple way to implement authentication and authorization features. This document will introduce how to use Auth.js to implement a new authentication provider.
TOC
Add New Authentication Provider
To add a new authentication provider in LobeChat (for example, adding Okta), you need to follow the steps below:
Pre-requisites: Check the Official Provider List
First, you need to check the Auth.js Provider List to see if your provider is already supported. If yes, you can directly use the SDK provided by Auth.js to implement the authentication feature.
Next, I will use Okta as an example to introduce how to add a new authentication provider.
Step 1: Add Authenticator Core Code
Open the src/app/api/auth/next-auth.ts
file and import next-auth/providers/okta
.
import { NextAuth } from 'next-auth';
import Auth0 from 'next-auth/providers/auth0';
import Okta from 'next-auth/providers/okta';
// Import Okta provider
Add the predefined server configuration.
// Import server configuration
const { OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_ISSUER } = getServerConfig();
const nextAuth = NextAuth({
providers: [
// ... Other providers
Okta({
clientId: OKTA_CLIENT_ID,
clientSecret: OKTA_CLIENT_SECRET,
issuer: OKTA_ISSUER,
}),
],
});
Step 2: Update Server Configuration Code
Open the src/config/server/app.ts
file and add Okta-related environment variables in the getAppConfig
function.
export const getAppConfig = () => {
// ... Other code
return {
// ... Other environment variables
OKTA_CLIENT_ID: process.env.OKTA_CLIENT_ID || '',
OKTA_CLIENT_SECRET: process.env.OKTA_CLIENT_SECRET || '',
OKTA_ISSUER: process.env.OKTA_ISSUER || '',
};
};
Step 3: Change Frontend Pages
Modify the signIn
function parameter in src/Features/Conversation/Error/OAuthForm.tsx
and `src/app/settings/common/Common.tsx
The default is auth0
, which you can change to okta
to switch to the Okta provider, or remove this parameter to support all added authentication services
This value is the id of the Auth.js provider, and you can read the source code of the corresponding next-auth/providers
module to read the default ID.
Step 4: Configure the Environment Variables
Add OKTA_CLIENT_ID
、OKTA_CLIENT_SECRET
、OKTA_ISSUER
environment variables when you deploy.
Step 5: Modify server-side user information processing logic
Get user information in the frontend
Use the useOAuthSession()
method in the frontend page to get the user information user
returned by the backend:
import { useOAuthSession } from '@/hooks/useOAuthSession';
const { user, isOAuthLoggedIn } = useOAuthSession();
The default type of user
is User
, and the type definition is:
interface User {
id?: string;
name?: string | null;
email?: string | null;
image?: string | null;
}
Modify user id
handling logic
The user.id
is used to identify users. When introducing a new OAuth identity provider, you need to handle the information carried in the OAuth callback in src/app/api/auth/next-auth.ts
. You need to select the user's id
from this information. Before that, we need to understand the data processing sequence of Auth.js
:
authorize --> jwt --> session
By default, in the jwt --> session
process, Auth.js
will automatically assign the user id
to account.providerAccountId
based on the login type. If you need to select a different value as the user id
, you need to implement the following handling logic:
callbacks: {
async jwt({ token, account, profile }) {
if (account) {
// You can select a different value from `account` or `profile`
token.userId = account.providerAccountId;
}
return token;
},
},
Customize session
return
If you want to carry more information about profile
and account
in the session
, according to the data processing order mentioned above in Auth.js
, you must first copy this information to the token
. For example, add the user avatar URL profile.picture
to the session
:
callbacks: {
async jwt({ token, profile, account }) {
if (profile && account) {
token.userId = account.providerAccountId;
+ token.avatar = profile.picture;
}
return token;
},
async session({ session, token }) {
if (session.user) {
session.user.id = token.userId ?? session.user.id;
+ session.user.avatar = token.avatar;
}
return session;
},
},
Then supplement the type definition for the new parameters:
declare module '@auth/core/jwt' {
interface JWT {
// ...
avatar?: string;
}
}
declare module 'next-auth' {
interface User {
avatar?: string;
}
}
Differentiate multiple authentication providers in the processing logic
If you have configured multiple authentication providers and their userId
mappings are different, you can use the account.provider
parameter in the jwt
method to get the default id of the identity provider and enter different processing logic.
callbacks: {
async jwt({ token, profile, account }) {
if (profile && account) {
if (account.provider === 'authing')
token.userId = account.providerAccountId ?? token.sub;
else if (acount.provider === 'auth0')
token.userId = profile.sub ?? token.sub;
else
// other providers
}
return token;
},
}
Now, you can use Okta as your provider to implement the authentication feature in LobeChat.