Grant Express Middleware
raw JSON →Grant Express is an Express.js middleware that acts as a handler for the Grant OAuth Proxy, simplifying authentication and authorization flows within Node.js applications. It integrates the robust Grant core library, which provides universal OAuth support for over 200 providers including Google, GitHub, Facebook, and many others. The current stable version for `grant-express` is 5.4.8. Grant is designed to abstract away the complexities of OAuth 1.0a, 2.0, and OpenID Connect, offering a unified configuration system and flexible integration with various HTTP frameworks and serverless environments. Its key differentiators include broad provider compatibility, a declarative configuration approach, and its ability to function as an embeddable OAuth client. The package facilitates managing OAuth callbacks, tokens, and session state efficiently, though users must provide their own session store. Release cadence is tied to the underlying Grant core library, which is actively maintained with updates for new providers, OAuth specification changes, and security patches.
Common errors
error Error: Grant: session store is required ↓
express-session (or an equivalent session management middleware) is installed and configured using app.use(session({ ... })) *before* mounting grant-express with app.use(Grant(config)). error OAuth error: redirect_uri_mismatch ↓
origin, prefix, and provider callback) and compare it precisely with the Authorized Redirect URIs listed in your OAuth provider's application settings. Pay attention to http vs https, domain, port, and path segments. error TypeError: Grant is not a function ↓
import Grant from 'grant-express';. For CommonJS, use const Grant = require('grant-express');. Ensure you are calling the imported Grant function to create the middleware, e.g., app.use(Grant(config)). error Cannot GET /connect/provider or Cannot POST /callback ↓
app.use(Grant(config)) is called correctly in your Express setup. Confirm that the prefix in your grantConfig matches the base path from which you expect Grant to handle routes (e.g., if prefix: '/auth', then /auth/github would initiate the flow). Warnings
breaking Express v5 introduced several breaking changes. While `grant-express` has a peer dependency on `express` `>=3.0.0`, ensuring full compatibility with the latest `express` v5 might require explicit updates to the `grant` core library or specific configuration adjustments. Consult the `express` migration guide and the `grant` documentation for any known incompatibilities. ↓
gotcha Grant requires a session middleware (e.g., `express-session`) to persist necessary state during the OAuth redirect flow. If not configured or placed correctly before `Grant` middleware, it will lead to runtime errors or failed authentication. ↓
gotcha OAuth client IDs and secrets (e.g., `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`) should never be hardcoded directly into your application code. This is a severe security risk. ↓
gotcha The OAuth `redirect_uri` (callback URL) must precisely match the URL registered with the OAuth provider (e.g., GitHub). Mismatches, including differences in `http` vs `https`, port numbers, or path segments, will cause `redirect_uri_mismatch` errors and prevent authentication. ↓
gotcha The `grant-express` package itself was last published five years ago, while the core `grant` project (which it relies on) appears to be more actively maintained. This could mean direct `grant-express` specific updates might be delayed, though core `grant` updates should still apply. ↓
Install
npm install grant-express yarn add grant-express pnpm add grant-express Imports
- Grant wrong
import { Grant } from 'grant-express'correctimport Grant from 'grant-express' - Grant wrong
const { Grant } = require('grant-express')correctconst Grant = require('grant-express') - GrantConfig
import type { GrantConfig } from 'grant'
Quickstart
import express from 'express';
import session from 'express-session';
import Grant from 'grant-express';
import dotenv from 'dotenv';
dotenv.config(); // Load environment variables
const app = express();
const port = process.env.PORT || 3000;
// IMPORTANT: Grant requires a session middleware
app.use(session({
secret: process.env.SESSION_SECRET ?? 'your-very-secret-key-that-should-be-random',
resave: false,
saveUninitialized: false,
cookie: { secure: process.env.NODE_ENV === 'production' }
}));
// Grant configuration for GitHub OAuth
const grantConfig = {
defaults: {
origin: `http://localhost:${port}`,
transport: 'session',
state: true
},
github: {
key: process.env.GITHUB_CLIENT_ID ?? '',
secret: process.env.GITHUB_CLIENT_SECRET ?? '',
scope: ['user:email', 'read:user'],
callback: '/callback'
}
};
// Mount the Grant middleware
app.use(Grant(grantConfig));
// Route to initiate GitHub OAuth
app.get('/login/github', (req, res) => {
// Redirects to /connect/github which Grant handles
res.redirect('/connect/github');
});
// Callback route to handle OAuth response
app.get('/callback', (req, res) => {
if (req.query.error) {
return res.status(400).send(`OAuth Error: ${req.query.error_description || req.query.error}`);
}
// Grant places the OAuth response data in req.session.grant.response
const { access_token, profile } = (req.session as any)?.grant?.response?.github?.raw || {};
if (access_token) {
res.send(`
<h1>Authentication Successful!</h1>
<p>Access Token: ${access_token}</p>
<p>User Profile (partial): ${profile ? JSON.stringify(profile.data, null, 2) : 'N/A'}</p>
<p><a href="/">Home</a></p>
`);
} else {
res.status(500).send('Authentication failed: No access token received.');
}
});
// Basic home route
app.get('/', (req, res) => {
res.send(`
<h1>Welcome to Grant Express Example</h1>
<p><a href="/login/github">Login with GitHub</a></p>
`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
console.log('Ensure GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, and SESSION_SECRET environment variables are set.');
});