GitHub Authentication Strategy for Remix Auth
remix-auth-github is a strategy for `remix-auth` that facilitates implementing login with GitHub in Remix applications. The current stable version is 3.0.2, and the package sees active maintenance with recent updates focused on bug fixes and dependency management. Key differentiators include its tight integration with the `remix-auth` ecosystem, providing a streamlined OAuth2 flow for GitHub. Since version 3.0.0, it relies on `arctic.js` for OAuth2 client functionality and has shifted its responsibility to primarily provide access tokens, requiring developers to explicitly fetch user profile data from GitHub's API if needed. It supports both Node.js and Cloudflare runtimes, making it versatile for various Remix deployment targets. This strategy focuses on providing the necessary tokens, allowing developers full control over how user data is retrieved and managed post-authentication.
Common errors
-
ReferenceError: globalThis.crypto is not defined
cause The runtime environment (e.g., an older Node.js version or a specific serverless function) lacks support for the `globalThis.crypto` API, which became a dependency for the internal `OAuth2Strategy` starting from v2.0.0.fixUpdate your Node.js version to 18 or newer, or ensure your deployment environment (like Cloudflare Workers) natively supports `globalThis.crypto`. -
Error: Authenticator is not configured for provider "github"
cause The strategy name provided to `authenticator.authenticate("provider-name", ...)` does not match the name specified when the `GitHubStrategy` was added to the authenticator instance (e.g., `authenticator.use(strategy, "my-github")`).fixVerify that the string used as the first argument in `authenticator.authenticate` (e.g., 'github') precisely matches the custom name you provided as the second argument to `authenticator.use` for `GitHubStrategy`. If no custom name was provided, the default is 'github'. -
Error: invalid_request: The redirect_uri provided is not valid for the client.
cause The `redirectURI` configured in your `GitHubStrategy` options within your Remix application does not exactly match one of the 'Authorization callback URL(s)' defined in your GitHub OAuth App settings on GitHub's developer portal.fixCarefully check and ensure that the `redirectURI` value in your `GitHubStrategy` configuration (e.g., `process.env.GITHUB_REDIRECT_URI`) is an exact, character-for-character match for an authorized callback URL registered with your GitHub OAuth App. -
TypeError: Cannot read properties of undefined (reading 'authenticate')
cause The `authenticator` instance has not been properly initialized or is not correctly exported/imported and accessible within the Remix route where `authenticator.authenticate` is being called.fixEnsure your `Authenticator` instance is correctly initialized with session storage (e.g., `export const authenticator = new Authenticator<User>(sessionStorage);`) and that it is properly imported into your Remix `loader` or `action` file.
Warnings
- breaking Version 3.0.0 introduced significant breaking changes. It mandates `remix-auth` v4 (supporting Remix and React Router v7). Strategy options were altered, and the strategy now uses `arctic.js` internally. Crucially, it no longer automatically fetches the user's GitHub profile; only OAuth tokens are provided, requiring manual API calls for profile data.
- breaking Version 2.0.0 introduced a breaking change: the underlying `OAuth2Strategy` now relies on `globalThis.crypto` being supported by the runtime. This can affect environments with older Node.js versions or specific serverless configurations.
- gotcha Since v3.0.0, the `GitHubStrategy`'s `verify` callback receives `tokens` but *not* a pre-fetched `profile` object. If your application needs GitHub user profile data (like `name`, `email`, `avatar`), you must use the `tokens.accessToken()` to make a subsequent `fetch` request to GitHub's user API (e.g., `https://api.github.com/user`).
Install
-
npm install remix-auth-github -
yarn add remix-auth-github -
pnpm add remix-auth-github
Imports
- GitHubStrategy
const GitHubStrategy = require('remix-auth-github');import { GitHubStrategy } from 'remix-auth-github'; - Authenticator
import Authenticator from 'remix-auth';
import { Authenticator } from 'remix-auth'; - GitHubProfile
import type { GitHubProfile } from 'remix-auth-github';
Quickstart
import { Authenticator } from 'remix-auth';
import { GitHubStrategy } from 'remix-auth-github';
import { createCookieSessionStorage } from '@remix-run/node'; // or '@remix-run/cloudflare/sessions'
import type { LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node'; // or '@remix-run/cloudflare'
// 1. Define your User type (to be stored in session)
interface User {
id: string;
name: string;
accessToken: string;
refreshToken: string | null;
// Potentially other GitHub profile data
}
// 2. Setup session storage
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "_session",
sameSite: "lax",
path: "/",
httpOnly: true,
secrets: [process.env.SESSION_SECRET ?? 's3cr3t-dev-key'], // IMPORTANT: Use a strong secret in production
secure: process.env.NODE_ENV === "production",
},
});
// 3. Setup Authenticator instance
export const authenticator = new Authenticator<User>(sessionStorage);
// 4. Configure GitHub Strategy
const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID ?? '';
const GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET ?? '';
const GITHUB_REDIRECT_URI = process.env.GITHUB_REDIRECT_URI ?? 'http://localhost:3000/auth/github/callback'; // Must match your GitHub App's callback URL
authenticator.use(
new GitHubStrategy(
{
clientId: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
redirectURI: GITHUB_REDIRECT_URI,
scopes: ["user:email", "read:user"], // Optional scopes
},
async ({ tokens, request }) => {
// In this function, you receive the OAuth tokens.
// Since v3.0.0, you must manually fetch user profile data if needed.
console.log('Received GitHub Tokens:', tokens);
const githubProfileResponse = await fetch('https://api.github.com/user', {
headers: {
Authorization: `token ${tokens.accessToken()}`,
},
});
const githubProfile = await githubProfileResponse.json();
console.log('GitHub Profile:', githubProfile);
// This is where you would lookup/create a user in your database
// based on the GitHub profile ID or email, and return your internal 'User' object.
return {
id: githubProfile.id.toString(),
name: githubProfile.name || githubProfile.login,
accessToken: tokens.accessToken(),
refreshToken: tokens.hasRefreshToken() ? tokens.refreshToken() : null,
};
}
),
"github" // This is the strategy name used in `authenticator.authenticate`
);
// 5. Example Route: Initiate GitHub Login (e.g., app/routes/auth.github.tsx action)
/*
export async function action({ request }: ActionFunctionArgs) {
await authenticator.authenticate("github", request, {
successRedirect: "/dashboard",
failureRedirect: "/login",
});
}
*/
// 6. Example Route: Handle GitHub Callback (e.g., app/routes/auth.github.callback.tsx loader)
/*
export async function loader({ request }: LoaderFunctionArgs) {
const user = await authenticator.authenticate("github", request, {
successRedirect: "/dashboard",
failureRedirect: "/login",
});
// User object is now in the session
return user;
}
*/