Atlas
Guides

Social Login Providers

Configure Google, GitHub, and Microsoft social login for Atlas managed auth.

Self-Hosted Only

Configuring social login providers requires editing the betterAuth() call in your Atlas source code. This applies to self-hosted deployments only. On app.useatlas.dev, social login providers are managed by the Atlas platform — go to Admin > Authentication to enable them for your workspace.

Atlas's managed auth (Better Auth) supports social login — no plugin required. Adding social providers requires a small configuration change to the betterAuth() call in packages/api/src/lib/auth/server.ts. This guide walks through setting up each provider.

Prerequisites

  • Managed auth enabled (BETTER_AUTH_SECRET + DATABASE_URL)
  • BETTER_AUTH_URL set to your API's public URL (e.g. https://api.example.com)
  • OAuth credentials from the provider you want to enable

How It Works

  1. User clicks a social login button (or your frontend calls auth.signIn.social())
  2. Browser redirects to the provider's OAuth consent screen
  3. Provider redirects back to Atlas at /api/auth/callback/{provider}
  4. Better Auth creates or links the user account and starts a session

Social login users go through the same admin bootstrap and invitation logic as email/password signups — the first user gets admin, invitation matches auto-assign roles, and ATLAS_ADMIN_EMAIL is respected. This logic runs on first sign-in (account creation). If a social login links to an existing account, the user keeps their current role.


Callback URL

Each provider needs a callback URL during OAuth app setup. The format is:

{BETTER_AUTH_URL}/api/auth/callback/{provider}
ProviderCallback URL
Googlehttps://api.example.com/api/auth/callback/google
GitHubhttps://api.example.com/api/auth/callback/github
Microsofthttps://api.example.com/api/auth/callback/microsoft

Replace https://api.example.com with your BETTER_AUTH_URL value. For local development, use http://localhost:3001.


Google

Create OAuth credentials

  1. Go to the Google Cloud Console
  2. Create a project (or select an existing one)
  3. Go to APIs & Services > Credentials
  4. Click Create Credentials > OAuth client ID
  5. Select Web application as the application type
  6. Under Authorized redirect URIs, add your callback URL:
    https://api.example.com/api/auth/callback/google
  7. Copy the Client ID and Client Secret

If you haven't configured the OAuth consent screen yet, Google will prompt you. Internal restricts sign-in to users within your Google Workspace organization (no verification needed). External allows any Google account but starts in "testing" mode (limited to 100 test users) until you submit for verification.

Set environment variables

# .env
GOOGLE_CLIENT_ID=123456789.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-...

Configure Atlas

Add a socialProviders block to the betterAuth() call in packages/api/src/lib/auth/server.ts, after the emailAndPassword configuration:

const instance = betterAuth({
  // ... existing config (database, secret, emailAndPassword) ...
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
  },
  // ... rest of config (session, plugins, databaseHooks) ...
});

Test

  1. Start Atlas: bun run dev
  2. Navigate to the login page
  3. Click Sign in with Google
  4. Complete the Google consent screen
  5. Verify you're redirected back and signed in

GitHub

Create an OAuth App

  1. Go to GitHub Settings > Developer settings > OAuth Apps
  2. Click New OAuth App
  3. Fill in the form:
    • Application name: Your app name (e.g. "Atlas")
    • Homepage URL: Your app URL (e.g. https://app.example.com)
    • Authorization callback URL:
      https://api.example.com/api/auth/callback/github
  4. Click Register application
  5. Copy the Client ID
  6. Click Generate a new client secret and copy it

GitHub only shows the client secret once. Copy it immediately after generating.

Set environment variables

# .env
GITHUB_CLIENT_ID=Iv1.abc123def456
GITHUB_CLIENT_SECRET=your-github-client-secret

Configure Atlas

const instance = betterAuth({
  // ... existing config ...
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },
});

Test

  1. Start Atlas: bun run dev
  2. Navigate to the login page
  3. Click Sign in with GitHub
  4. Authorize the OAuth app on GitHub
  5. Verify you're redirected back and signed in

Microsoft (Entra ID)

Register an application

  1. Go to the Azure Portal > App registrations
  2. Click New registration
  3. Fill in the form:
    • Name: Your app name (e.g. "Atlas")
    • Supported account types: Choose based on your needs:
      • Single tenant — Only your organization
      • Multitenant — Any Microsoft work/school account
      • Multitenant + personal — Any Microsoft account (default)
    • Redirect URI: Select Web and enter:
      https://api.example.com/api/auth/callback/microsoft
  4. Click Register
  5. Copy the Application (client) ID from the overview page
  6. Copy the Directory (tenant) ID if you're restricting to your organization

Create a client secret

  1. In your app registration, go to Certificates & secrets
  2. Click New client secret
  3. Add a description and set an expiration
  4. Click Add
  5. Copy the secret Value (not the Secret ID)

The secret value is only shown once. Copy it immediately after creation. Set a calendar reminder before expiration to rotate the secret.

Set environment variables

# .env
MICROSOFT_CLIENT_ID=12345678-abcd-efgh-ijkl-1234567890ab
MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret

# Optional: restrict to a specific tenant (default: "common" = any Microsoft account)
MICROSOFT_TENANT_ID=your-tenant-id

Configure Atlas

const instance = betterAuth({
  // ... existing config ...
  socialProviders: {
    microsoft: {
      clientId: process.env.MICROSOFT_CLIENT_ID!,
      clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
      tenantId: process.env.MICROSOFT_TENANT_ID || "common",
    },
  },
});

Tenant ID values:

ValueWho can sign in
commonAny Microsoft account (personal + work/school)
organizationsAny work/school account
consumersPersonal Microsoft accounts only
{tenant-id}Only accounts in that specific directory

Test

  1. Start Atlas: bun run dev
  2. Navigate to the login page
  3. Click Sign in with Microsoft
  4. Sign in with a Microsoft account
  5. Verify you're redirected back and signed in

Multiple Providers

Enable any combination of providers in a single configuration:

const instance = betterAuth({
  // ... existing config ...
  emailAndPassword: { enabled: true },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
    microsoft: {
      clientId: process.env.MICROSOFT_CLIENT_ID!,
      clientSecret: process.env.MICROSOFT_CLIENT_SECRET!,
      tenantId: process.env.MICROSOFT_TENANT_ID || "common",
    },
  },
});

Social providers work alongside email/password. Users who sign up via a social provider can later add a password, and vice versa. Better Auth links accounts by email address when the provider returns a verified email — if a user signs in with Google using the same email they previously used for email/password signup, the accounts are linked. Google and Microsoft return verified emails by default. For GitHub, the user's primary email must be verified on GitHub for automatic linking to work.


Frontend Integration

The Atlas web UI currently supports email/password sign-in. To add social login buttons, use the Better Auth client in your frontend:

import { createAuthClient } from "better-auth/react";

const auth = createAuthClient({
  baseURL: "https://api.example.com",
});

// Redirect to provider's OAuth consent screen
await auth.signIn.social({ provider: "google" });
await auth.signIn.social({ provider: "github" });
await auth.signIn.social({ provider: "microsoft" });

After successful authentication, the user is redirected back to your app with an active session.


Troubleshooting

Redirect URI mismatch

Symptom: OAuth provider returns an error like "redirect_uri_mismatch" or "Invalid redirect URI".

Fix: The callback URL registered with the provider must exactly match what Better Auth generates. Check:

  • Protocol: https:// vs http:// (use http:// only for localhost)
  • Trailing slashes: most providers are strict about this
  • Port: include the port for non-standard ports (e.g. http://localhost:3001/api/auth/callback/google)
  • BETTER_AUTH_URL must be set correctly — Better Auth uses it to construct callback URLs

"email_not_found" error with GitHub

Symptom: GitHub sign-in fails with an email-related error.

Fix: GitHub OAuth does not return the user's email if their email is set to private. Better Auth requests the user:email scope automatically, but the user must have at least one verified, primary email on GitHub. Ask the user to:

  1. Go to GitHub email settings
  2. Ensure at least one email is verified (has a green checkmark)
  3. Ensure a primary email is set

User lands on wrong role after social login

Symptom: A user signs in via social provider but gets analyst instead of admin.

Explanation: Social login goes through the same bootstrap logic as email/password:

  • If ATLAS_ADMIN_EMAIL matches the social account's email → admin
  • If no admin exists yet → first signup gets admin
  • If a pending invitation matches the email → invited role is assigned
  • Otherwise → analyst (the defaultRole from the admin plugin)

Check that ATLAS_ADMIN_EMAIL matches the email the provider returns (case-insensitive).

Microsoft: "AADSTS700016" application error

Symptom: Microsoft login fails with error code AADSTS700016.

Fix: The Application (client) ID is incorrect or the app registration is not in the expected tenant. Verify:

  • MICROSOFT_CLIENT_ID matches the Application (client) ID (not the Object ID)
  • MICROSOFT_TENANT_ID matches the directory where the app is registered (or use common for multi-tenant)

Microsoft: client secret expired

Symptom: Microsoft login suddenly stops working.

Fix: Entra ID client secrets have an expiration date. Generate a new secret in Certificates & secrets and update MICROSOFT_CLIENT_SECRET. Set a reminder to rotate before the next expiration.

Symptom: Social login completes but the user appears unauthenticated on the frontend.

Fix: If your API and frontend are on different origins, ensure cross-origin cookies are configured:

ATLAS_CORS_ORIGIN=https://app.example.com
BETTER_AUTH_TRUSTED_ORIGINS=https://app.example.com
BETTER_AUTH_URL=https://api.example.com

See Cross-origin deployment for details.

Account linking

When a user signs in with a social provider using the same verified email as an existing account, Better Auth links the accounts. The user can then sign in with either method. If you see duplicate accounts, check whether:

  • The social provider is returning a different email than expected (e.g. a personal vs. work Microsoft account)
  • The GitHub user's email is unverified (unverified emails are not linked automatically)

On this page