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:
- Provider factories -- Functions that create provider objects for different authentication strategies.
- 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
| Provider | Factory | Use Case |
|---|---|---|
| Email/Password | createCredentialsAuthProvider | Traditional login forms |
createGoogleAuthProvider | "Sign in with Google" | |
| GitHub | createGitHubAuthProvider | "Sign in with GitHub" |
| Microsoft | createMicrosoftAuthProvider | Azure AD / Entra ID / Microsoft accounts |
createFacebookAuthProvider | "Sign in with Facebook" | |
| X (Twitter) | createXAuthProvider | "Sign in with X" |
| Auth0 | createAuth0AuthProvider | Auth0 tenant login |
| Okta | createOktaAuthProvider | Okta workforce / customer identity |
| Any OIDC | createOIDCAuthProvider | Any 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 nullimport { 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()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
- Tutorial: Build Email/Password and GitHub Login -- Step-by-step guide to implementing both authentication strategies.
- API Reference -- Complete documentation of every provider factory, flow function, and type.