---
title: New Authentication Provider Guide
description: Learn how to implement a new authentication provider using Auth.js in LobeHub.
tags:
  - Authentication
  - Auth.js
  - LobeHub
  - Okta
  - OAuth
---

# New Authentication Provider Guide

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

## Architecture Overview

To add a new authentication provider in LobeHub (for example, adding Okta), you need to follow the steps below:

| Type      | Description                                 | Examples                         |
| --------- | ------------------------------------------- | -------------------------------- |
| `builtin` | Providers natively supported by Better Auth | Google, GitHub, Microsoft, Apple |
| `generic` | Implemented via Generic OIDC/OAuth plugin   | Okta, Auth0, Keycloak, etc.      |

## Adding a New SSO Provider

Using **Okta** as an example, here's how to add a `generic` type provider.

### Step 1: Create Provider Definition File

Create `okta.ts` in `src/libs/better-auth/sso/providers/`:

```ts
import { authEnv } from '@/envs/auth';

import { buildOidcConfig } from '../helpers';
import type { GenericProviderDefinition } from '../types';

const provider: GenericProviderDefinition<{
  AUTH_OKTA_ID: string;
  AUTH_OKTA_ISSUER: string;
  AUTH_OKTA_SECRET: string;
}> = {
  // Build OIDC configuration
  build: (env) =>
    buildOidcConfig({
      clientId: env.AUTH_OKTA_ID,
      clientSecret: env.AUTH_OKTA_SECRET,
      issuer: env.AUTH_OKTA_ISSUER,
      overrides: {
        // Optional: customize user profile mapping
        mapProfileToUser: (profile) => ({
          email: profile.email,
          name: profile.name ?? profile.preferred_username ?? profile.email ?? profile.sub,
        }),
      },
      providerId: 'okta',
    }),

  // Environment variable validation
  checkEnvs: () => {
    return !!(authEnv.AUTH_OKTA_ID && authEnv.AUTH_OKTA_SECRET && authEnv.AUTH_OKTA_ISSUER)
      ? {
          AUTH_OKTA_ID: authEnv.AUTH_OKTA_ID,
          AUTH_OKTA_ISSUER: authEnv.AUTH_OKTA_ISSUER,
          AUTH_OKTA_SECRET: authEnv.AUTH_OKTA_SECRET,
        }
      : false;
  },

  // Provider ID (used in AUTH_SSO_PROVIDERS)
  id: 'okta',
  type: 'generic',
};

export default provider;
```

### Step 2: Register the Provider

Import and register in `src/libs/better-auth/sso/index.ts`:

```ts
// Import provider
import Okta from './providers/okta';

// Add to providerDefinitions array
const providerDefinitions = [
  // ... other providers
  Okta,
] as const;
```

### Step 3: Add Environment Variable Types

Add type declarations in `src/envs/auth.ts`:

```ts
// Add to ProcessEnv interface
AUTH_OKTA_ID?: string;
AUTH_OKTA_SECRET?: string;
AUTH_OKTA_ISSUER?: string;

// Add to getAuthConfig server schema
AUTH_OKTA_ID: z.string().optional(),
AUTH_OKTA_SECRET: z.string().optional(),
AUTH_OKTA_ISSUER: z.string().optional(),

// Add to runtimeEnv
AUTH_OKTA_ID: process.env.AUTH_OKTA_ID,
AUTH_OKTA_SECRET: process.env.AUTH_OKTA_SECRET,
AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
```

### Step 4: Update Documentation (Optional)

Add provider documentation in `docs/self-hosting/auth.mdx` and `docs/self-hosting/auth.zh-CN.mdx`.

## Adding a Built-in Provider

For providers natively supported by Better Auth (e.g., Discord), the steps differ slightly:

### Step 1: Create Provider Definition File

```ts
import { authEnv } from '@/envs/auth';

import type { BuiltinProviderDefinition } from '../types';

const provider: BuiltinProviderDefinition<{
  AUTH_DISCORD_ID: string;
  AUTH_DISCORD_SECRET: string;
}> = {
  build: (env) => ({
    clientId: env.AUTH_DISCORD_ID,
    clientSecret: env.AUTH_DISCORD_SECRET,
  }),
  checkEnvs: () => {
    return !!(authEnv.AUTH_DISCORD_ID && authEnv.AUTH_DISCORD_SECRET)
      ? {
          AUTH_DISCORD_ID: authEnv.AUTH_DISCORD_ID,
          AUTH_DISCORD_SECRET: authEnv.AUTH_DISCORD_SECRET,
        }
      : false;
  },
  id: 'discord',
  type: 'builtin',
};

export default provider;
```

### Step 2: Update Constants File

Add to `src/libs/better-auth/constants.ts`:

```ts
export const BUILTIN_BETTER_AUTH_PROVIDERS = [
  'apple',
  'google',
  'github',
  'cognito',
  'microsoft',
  'discord', // Add new provider
] as const;
```

## Callback URL Format

When configuring OAuth applications, use these callback URL formats:

- **Built-in providers**: `https://yourdomain.com/api/auth/callback/{providerId}`
- **Generic OIDC**: `https://yourdomain.com/api/auth/callback/{providerId}`

## Using the New Provider

After configuring environment variables, enable in `AUTH_SSO_PROVIDERS`:

```bash
AUTH_SSO_PROVIDERS=google,github,okta
AUTH_OKTA_ID=your-client-id
AUTH_OKTA_SECRET=your-client-secret
AUTH_OKTA_ISSUER=https://your-domain.okta.com
```

Now, you can use Okta as your provider to implement the authentication feature in LobeHub.
