Skip to content

auth Overview

The remix/auth package handles user authentication -- the process of verifying that someone is who they claim to be. It supports three approaches: credentials-based login (email and password), OAuth 2.0 with built-in providers for popular services, and OpenID Connect (OIDC) for any standards-compliant identity provider.

Key Concepts

Before diving in, here are a few terms you will encounter:

  • Authentication -- Verifying a user's identity. "Who are you?" (Distinct from authorization, which is "What are you allowed to do?")
  • OAuth 2.0 -- An industry-standard protocol that lets users sign in to your app using their existing account on another service (Google, GitHub, etc.) without sharing their password with you.
  • OIDC (OpenID Connect) -- A layer on top of OAuth 2.0 that adds a standardized way to get user profile information.
  • Provider -- A configuration object that describes how to authenticate with a specific service (e.g. Google, GitHub) or mechanism (e.g. email/password).
  • Auth flow -- The sequence of steps a user goes through to prove their identity and gain access.

What It Does

The remix/auth package gives you two things:

  1. Provider factories -- Functions that create provider objects for different authentication strategies.
  2. Flow functions -- Functions that execute the steps of an authentication flow (verify credentials, redirect to an OAuth provider, handle the callback).

It does not manage sessions, store user data, or protect routes. Those responsibilities belong to remix/session, remix/session-middleware, and remix/auth-middleware, respectively.

Built-in Providers

ProviderFactoryUse Case
Email/PasswordcreateCredentialsAuthProviderTraditional login forms
GooglecreateGoogleAuthProvider"Sign in with Google"
GitHubcreateGitHubAuthProvider"Sign in with GitHub"
MicrosoftcreateMicrosoftAuthProviderAzure AD / Entra ID / Microsoft accounts
FacebookcreateFacebookAuthProvider"Sign in with Facebook"
X (Twitter)createXAuthProvider"Sign in with X"
Auth0createAuth0AuthProviderAuth0 tenant login
OktacreateOktaAuthProviderOkta workforce / customer identity
Any OIDCcreateOIDCAuthProviderAny OpenID Connect-compliant provider

The Auth Flow

Credentials Flow

The credentials flow is the simplest. The user submits a form with their email and password, your server verifies them, and then stores the user's identity in a session.

User submits form ──> verifyCredentials() ──> Identity or null
ts
import { createCredentialsAuthProvider, verifyCredentials } from 'remix/auth'
import { Session } from 'remix/session'
import bcrypt from 'bcrypt'

let credentialsAuth = createCredentialsAuthProvider({
  name: 'credentials',

  parse(context) {
    let data = context.get(FormData)
    return {
      email: data.get('email') as string,
      password: data.get('password') as string,
    }
  },

  async verify({ email, password }) {
    let user = await db.findUserByEmail(email)
    if (!user) return null

    let valid = await bcrypt.compare(password, user.passwordHash)
    if (!valid) return null

    return { id: user.id, email: user.email, name: user.name }
  },
})

// In your login route handler:
router.map(loginAction, async ({ context }) => {
  let identity = await verifyCredentials(credentialsAuth, context)

  if (!identity) {
    return new Response('Invalid email or password', { status: 401 })
  }

  let session = context.get(Session)
  session.set('userId', identity.id)
  session.regenerateId()

  return new Response(null, { status: 302, headers: { Location: '/' } })
})

OAuth / External Auth Flow

The OAuth flow involves three steps spread across two HTTP requests:

1. User clicks "Sign in with GitHub"
   ──> startExternalAuth() ──> Redirect to GitHub

2. GitHub redirects back to your callback URL
   ──> finishExternalAuth() ──> Profile + Tokens

3. You store the user in your database and session
   ──> completeAuth() or manual session.set()
ts
import {
  createGitHubAuthProvider,
  startExternalAuth,
  finishExternalAuth,
} from 'remix/auth'
import { Session } from 'remix/session'

let githubAuth = createGitHubAuthProvider({
  clientId: process.env.GITHUB_CLIENT_ID!,
  clientSecret: process.env.GITHUB_CLIENT_SECRET!,
  redirectUri: 'http://localhost:3000/auth/github/callback',
  scopes: ['user:email'],
})

// Step 1: Redirect to GitHub
router.get(githubLoginRoute, async ({ context }) => {
  return startExternalAuth(githubAuth, context)
})

// Step 2-3: Handle callback, create/find user, set session
router.get(githubCallbackRoute, async ({ context }) => {
  let result = await finishExternalAuth(githubAuth, context)
  if (!result) {
    return new Response('Authentication failed', { status: 401 })
  }

  let user = await findOrCreateUser(result.profile.email, result.profile.name)

  let session = context.get(Session)
  session.set('userId', user.id)
  session.regenerateId()

  return new Response(null, { status: 302, headers: { Location: '/' } })
})

How It Fits Together

The remix/auth package handles the identity verification step. To build a complete authentication system, you will typically use it alongside:

  • remix/session -- Stores the authenticated user's ID across requests.
  • remix/session-middleware -- Loads and saves the session on every request.
  • remix/auth-middleware -- Reads the session to determine who the current user is, and protects routes that require authentication.
  • remix/cookie -- Configures the session cookie (signing, expiration, security attributes).

Next Steps

Released under the MIT License.