@auth/express
@auth/express
is currently experimental. The API will change in the future.
Express Auth is the official Express integration for Auth.js. It provides a simple way to add authentication to your Express app in a few lines of code.
Installation
npm install @auth/express
Usage
import { ExpressAuth } from "@auth/express"
import GitHub from "@auth/express/providers/github"
import express from "express"
const app = express()
// If app is served through a proxy, trust the proxy to allow HTTPS protocol to be detected
// https://expressjs.com/en/guide/behind-proxies.html
app.set('trust proxy', true)
app.use("/auth/*", ExpressAuth({ providers: [ GitHub ] }))
Don’t forget to set the AUTH_SECRET
environment variable. This should be a minimum of 32 characters, random string. On UNIX systems you can use openssl rand -hex 32
or check out https://generate-secret.vercel.app/32
.
You will also need to load the environment variables into your runtime environment. For example in Node.js with a package like dotenv
or Deno.env
in Deno.
Provider Configuration
The callback URL used by the providers must be set to the following, unless you mount the ExpressAuth
handler on a different path:
[origin]/auth/callback/[provider]
Signing in and signing out
Once your application is mounted you can sign in or out by making requests to the following REST API endpoints from your client-side code.
NB: Make sure to include the csrfToken
in the request body for all sign-in and sign-out requests.
Managing the session
If you are using Express with a template engine (e.g EJS, Pug), you can make the session data available to all routes via middleware as follows
import { getSession } from "@auth/express"
export function authSession(req: Request, res: Response, next: NextFunction) {
res.locals.session = await getSession(req)
next()
}
app.use(authSession)
// Now in your route
app.get("/", (req, res) => {
const { session } = res.locals
res.render("index", { user: session?.user })
})
Authorization
You can protect routes by checking for the presence of a session and then redirect to a login page if the session is not present. This can either be done per route, or for a group of routes using a middleware such as the following:
export async function authenticatedUser(
req: Request,
res: Response,
next: NextFunction
) {
const session = res.locals.session ?? (await getSession(req, authConfig))
if (!session?.user) {
res.redirect("/login")
} else {
next()
}
}
Per Route
To protect a single route, simply add the middleware to the route as follows:
// This route is protected
app.get("/profile", authenticatedUser, (req, res) => {
const { session } = res.locals
res.render("profile", { user: session?.user })
})
// This route is not protected
app.get("/", (req, res) => {
res.render("index")
})
app.use("/", root)
Per Group of Routes
To protect a group of routes, define a router and add the middleware to the router as follows:
import { Router } from "express"
const router = Router()
router.use(authenticatedUser) // All routes defined after this will be protected
router.get("/", (req, res) => {
res.render("protected")
})
export default router
Then we mount the router as follows:
import protected from "./routes/protected.route"
app.use("/protected", protected)
Notes on ESM
@auth/express is ESM only. This means your package.json must contain "type": "module"
and tsconfig.json should contain "module": "NodeNext"
or ESNext
.
File imports must use the .js
extension, e.g. import { MyRouter } from "./my-router.js"
.
Your dev server should either be run with tsx with tsx index.ts
(fast startup, with no type checking), or ts-node with ‘node —loader ts-node/esm index.ts’ (slower startup, but has type checking).
While it is NOT recommended, if you wish to use @auth/express within a CommonJS project without migrating and making the above changes, you can run the dev server with tsx and may be able to compile with pkgroll. Add ‘“name”: “./dist/index.js”’ or ‘“name”: “./dist/index.mjs”’ to your package.json and run ‘pkgroll’ to compile with both ESM and CommonJS support. For new projects it is recommended to just use ESM.
AuthError
Base error class for all Auth.js errors.
It’s optimized to be printed in the server logs in a nicely formatted way
via the logger.error
option.
Extends
Constructors
new AuthError(message, errorOptions)
new AuthError(message?, errorOptions?): AuthError
Parameters
Parameter | Type |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
Returns
Overrides
Error.constructor
Properties
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
Type declaration
err?
optional err: Error;
Overrides
Error.cause
message
message: string;
Inherited from
Error.message
name
name: string;
Inherited from
Error.name
stack?
optional stack: string;
Inherited from
Error.stack
type
type: ErrorType;
The error type. Used to identify the error in the logs.
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
Optional override for formatting stack traces
See
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
Parameters
Parameter | Type |
---|---|
err | Error |
stackTraces | CallSite [] |
Returns
any
Inherited from
Error.prepareStackTrace
stackTraceLimit
static stackTraceLimit: number;
Inherited from
Error.stackTraceLimit
Methods
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
Create .stack property on a target object
Parameters
Parameter | Type |
---|---|
targetObject | object |
constructorOpt ? | Function |
Returns
void
Inherited from
Error.captureStackTrace
CredentialsSignin
Can be thrown from the authorize
callback of the Credentials provider.
When an error occurs during the authorize
callback, two things can happen:
- The user is redirected to the signin page, with
error=CredentialsSignin&code=credentials
in the URL.code
is configurable. - If you throw this error in a framework that handles form actions server-side, this error is thrown, instead of redirecting the user, so you’ll need to handle.
Extends
Constructors
new CredentialsSignin(message, errorOptions)
new CredentialsSignin(message?, errorOptions?): CredentialsSignin
Parameters
Parameter | Type |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
Returns
Inherited from
Properties
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
Type declaration
err?
optional err: Error;
Inherited from
code
code: string;
The error code that is set in the code
query parameter of the redirect URL.
⚠ NOTE: This property is going to be included in the URL, so make sure it does not hint at sensitive errors.
The full error is always logged on the server, if you need to debug.
Generally, we don’t recommend hinting specifically if the user had either a wrong username or password specifically, try rather something like “Invalid credentials”.
message
message: string;
Inherited from
name
name: string;
Inherited from
stack?
optional stack: string;
Inherited from
type
type: ErrorType;
The error type. Used to identify the error in the logs.
Inherited from
kind
static kind: string;
Inherited from
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
Optional override for formatting stack traces
See
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
Parameters
Parameter | Type |
---|---|
err | Error |
stackTraces | CallSite [] |
Returns
any
Inherited from
stackTraceLimit
static stackTraceLimit: number;
Inherited from
type
static type: string;
Methods
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
Create .stack property on a target object
Parameters
Parameter | Type |
---|---|
targetObject | object |
constructorOpt ? | Function |
Returns
void
Inherited from
Account
Usually contains information about the provider being used
and also extends TokenSet
, which is different tokens returned by OAuth Providers.
Extends
Partial
<TokenEndpointResponse
>
Properties
access_token?
optional readonly access_token: string;
Inherited from
Partial.access_token
authorization_details?
optional readonly authorization_details: AuthorizationDetails[];
Inherited from
Partial.authorization_details
expires_at?
optional expires_at: number;
Calculated value based on TokenEndpointResponse.expires_in.
It is the absolute timestamp (in seconds) when the TokenEndpointResponse.access_token expires.
This value can be used for implementing token rotation together with TokenEndpointResponse.refresh_token.
See
- https://authjs.dev/guides/refresh-token-rotation#database-strategy
- https://www.rfc-editor.org/rfc/rfc6749#section-5.1
expires_in?
optional readonly expires_in: number;
Inherited from
Partial.expires_in
id_token?
optional readonly id_token: string;
Inherited from
Partial.id_token
provider
provider: string;
Provider’s id for this account. E.g. “google”. See the full list at https://authjs.dev/reference/core/providers
providerAccountId
providerAccountId: string;
This value depends on the type of the provider being used to create the account.
- oauth/oidc: The OAuth account’s id, returned from the
profile()
callback. - email: The user’s email address.
- credentials:
id
returned from theauthorize()
callback
refresh_token?
optional readonly refresh_token: string;
Inherited from
Partial.refresh_token
scope?
optional readonly scope: string;
Inherited from
Partial.scope
token_type?
optional readonly token_type: Lowercase<string>;
NOTE: because the value is case insensitive it is always returned lowercased
Inherited from
Partial.token_type
type
type: ProviderType;
Provider’s type for this account
userId?
optional userId: string;
id of the user this account belongs to
See
https://authjs.dev/reference/core/adapters#adapteruser
DefaultSession
Extended by
Properties
expires
expires: string;
user?
optional user: User;
Profile
The user info returned from your OAuth provider.
See
https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
Indexable
[claim
: string
]: unknown
Properties
address?
optional address: null | {
country: null | string;
formatted: null | string;
locality: null | string;
postal_code: null | string;
region: null | string;
street_address: null | string;
};
birthdate?
optional birthdate: null | string;
email?
optional email: null | string;
email_verified?
optional email_verified: null | boolean;
family_name?
optional family_name: null | string;
gender?
optional gender: null | string;
given_name?
optional given_name: null | string;
id?
optional id: null | string;
locale?
optional locale: null | string;
middle_name?
optional middle_name: null | string;
name?
optional name: null | string;
nickname?
optional nickname: null | string;
phone_number?
optional phone_number: null | string;
picture?
optional picture: any;
preferred_username?
optional preferred_username: null | string;
profile?
optional profile: null | string;
sub?
optional sub: null | string;
updated_at?
optional updated_at: null | string | number | Date;
website?
optional website: null | string;
zoneinfo?
optional zoneinfo: null | string;
Session
The active session of the logged in user.
Extends
Properties
expires
expires: string;
Inherited from
user?
optional user: User;
Inherited from
User
The shape of the returned object in the OAuth providers’ profile
callback,
available in the jwt
and session
callbacks,
or the second parameter of the session
callback, when using a database.
Extended by
Properties
email?
optional email: null | string;
id?
optional id: string;
image?
optional image: null | string;
name?
optional name: null | string;
ExpressAuthConfig
type ExpressAuthConfig: Omit<AuthConfig, "raw">;
GetSessionResult
type GetSessionResult: Promise<Session | null>;
customFetch
const customFetch: unique symbol;
This option allows you to override the default fetch
function used by the provider
to make requests to the provider’s OAuth endpoints directly.
Used incorrectly, it can have security implications.
It can be used to support corporate proxies, custom fetch libraries, cache discovery endpoints, add mocks for testing, logging, set custom headers/params for non-spec compliant providers, etc.
Example
import { Auth, customFetch } from "@auth/core"
import GitHub from "@auth/core/providers/github"
const dispatcher = new ProxyAgent("my.proxy.server")
function proxy(...args: Parameters<typeof fetch>): ReturnType<typeof fetch> {
return undici(args[0], { ...(args[1] ?? {}), dispatcher })
}
const response = await Auth(request, {
providers: [GitHub({ [customFetch]: proxy })]
})
See
- https://undici.nodejs.org/#/docs/api/ProxyAgent?id=example-basic-proxy-request-with-local-agent-dispatcher
- https://authjs.dev/guides/corporate-proxy
ExpressAuth()
ExpressAuth(config): (req, res, next) => Promise<void>
Parameters
Parameter | Type |
---|---|
config | ExpressAuthConfig |
Returns
Function
Parameters
Parameter Type req
Request
<ParamsDictionary
,any
,any
,ParsedQs
,Record
<string
,any
>>res
Response
<any
,Record
<string
,any
>>next
NextFunction
Returns
Promise
<void
>
getSession()
getSession(req, config): GetSessionResult
Parameters
Parameter | Type |
---|---|
req | Request <ParamsDictionary , any , any , ParsedQs , Record <string , any >> |
config | ExpressAuthConfig |