# New Authentication Provider Guide

LobeChat uses [Auth.js v5](https://authjs.dev/) 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](#add-new-authentication-provider)
  - [Pre-requisites: Check the Official Provider List](#pre-requisites-check-the-official-provider-list)
  - [Step 1: Add Authenticator Core Code](#step-1-add-authenticator-core-code)
  - [Step 2: Update Server Configuration Code](#step-2-update-server-configuration-code)
  - [Step 3: Change Frontend Pages](#step-3-change-frontend-pages)
  - [Step 4: Configure the Environment Variables](#step-4-configure-the-environment-variables)
  - [Step 5: Modify server-side user information processing logic](#step-5-modify-server-side-user-information-processing-logic)

## 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](https://authjs.dev/reference/core/providers) 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](https://authjs.dev/reference/core/providers/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`.

```ts
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.

```ts
// 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.

```ts
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:

```ts
import { useOAuthSession } from '@/hooks/useOAuthSession';

const { user, isOAuthLoggedIn } = useOAuthSession();
```

The default type of `user` is `User`, and the type definition is:

```ts
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`:

```txt
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](https://authjs.dev/reference/core/types#provideraccountid). If you need to select a different value as the user `id`, you need to implement the following handling logic:

```ts
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`:

```diff
  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:

```ts
declare module '@auth/core/jwt' {
  interface JWT {
    // ...
    avatar?: string;
  }
}

declare module 'next-auth' {
  interface User {
    avatar?: string;
  }
}
```

> [More built-in type extensions in Auth.js](https://authjs.dev/getting-started/typescript#module-augmentation)

#### 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.

```ts
  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.
