
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@gel/auth-express
Advanced tools
@gel/auth-expressThis library provides a set of utilities to help you integrate authentication into your Express application. It supports various authentication methods including OAuth, email/password, and session-based authentication.
This package is published on npm and can be installed with your package manager of choice.
npm install @gel/auth-express
Note: We have tested this library against the latest version of Express v4 with the types provided at DefinitelyTyped and have set up peerDependencies based on typical usage with npm.
Prerequisites:
crypto global, you will need to start Node with --experimental-global-webcrypto. You can add this option to your NODE_OPTIONS environment variable, like NODE_OPTIONS='--experimental-global-webcrypto' in the appropriate .env file.auth extension in your Gel schema, and have configured the extension with some providers (you can do this in CLI or Gel UI). Refer to the auth extension docs for details on how to do this.body-parser: both JSON and urlencodedcookie-parserimport express from "express";
import cookieParser from "cookie-parser";
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
This library provides a few affordances for adding Gel Auth to your existing Express app:
ExpressAuth classAfter configuring the Gel Auth extension, you can set up the various auth routes with our route builders.
Start by instantiating an ExpressAuth object by passing it a configured Gel client and some options:
import { createClient } from "gel";
import createExpressAuth from "@gel/auth-express";
import * as expressAuth from "@gel/auth-express";
const client = createClient();
const auth = createExpressAuth(client, {
  baseUrl: "http://localhost:3000", // Put the URL to your Express app here
});
createSessionMiddlewareWe provide a middleware factory that will attach an ExpressAuthSession object to your request object, which you can use to make authenticated queries, or protect routes.
app.use(auth.createSessionMiddleware());
You can then use the SessionRequest type for your route's request parameter, which extends the Express Request type with session?: ExpressAuthSession.
app.get("/dashboard", (req: expressAuth.SessionRequest, res) => {
  if (!(await req.session?.isSignedIn())) {
    return res.redirect("/auth/builtin/signin");
  }
  // Render a template using Pug or EJS
  res.render("dashboard", {
    title: "Dashboard",
    message: "Welcome to your dashboard!",
  });
});
requireAuth middlewareYou can centralize the logic to redirect unauthenticated routes into a custom middleware like this:
function requireAuth(
  req: expressAuth.SessionRequest,
  res: Response,
  next: NextFunction,
) {
  if (!(await req.session?.isSignedIn())) {
    return res.redirect("/auth/builtin/signin");
  }
  next();
}
Then you can use this to protect your route like this:
app.get("/dashboard", requireAuth, (req: expressAuth.SessionRequest, res) => {
  // Render a template using Pug or EJS
  res.render("dashboard", {
    title: "Dashboard",
    message: "Welcome to your dashboard!",
  });
});
Route handlers can be added either using one or more of our "router factories", or by constructing your own Express Router object, and attaching the necessary middleware to routes that you configure yourself. The factory pattern makes it easy to quickly get a standardized set of routes to handle either the built-in UI, or some combination of email/password and/or OAuth routes. For maximum control over route locations, custom middleware patterns, or integration into existing router structures, you can use the router middleware.
signoutWe provide a "signout" route handler that is used to reset the req.session, and remove the authentication cookie from the browser session. It works across all of the various authentication strategies, so it is included as a bare middleware that you add to your Express router yourself, adding a route handler for redirecting after the sign-out completes.
app.get("/signout", expressAuth.signout, (req, res) => {
  res.redirect("/goodbye");
});
createBuiltinRouterWhen using the built-in UI, be sure to set your redirect_to and redirect_to_on_signup values in the configuration to the route that the callback is mounted to, adding ?isSignUp=true to the redirect_to_on_signup value.
callback: (express.RouteHandler | express.ErrorHandler)[], required, Once the authentication flow completes, this callback will be called, and you must return a terminating Express route handler here. Typically, you'll redirect to elsewhere in your app based on req.isSignUp.const builtinRouter = auth.createBuiltinRouter({
  callback: [
    (req: expressAuth.CallbackRequest, res, next) => {
      if (req.isSignUp) {
        return res.redirect("/onboarding");
      }
      res.redirect("/");
    },
  ],
});
app.use("/auth", builtinRouter);
// Creates the following routes:
// - GET /auth/signin: Redirects to built-in UI's sign in page
// - GET /auth/signup: Redirects to built-in UI's sign up page
// - GET /auth/callback: Handles successful authentication. Typically you'll create a new user if `isSignUp` is true, and redirect appropriately.
createEmailPasswordRouterrouterPath: string, required, This is the path relative to the baseUrl given that was configured when creating the ExpressAuth object that this router will be attached to. This is used to build the URL to the email verification path configured by the router factory.signIn: (express.RouteHandler | express.ErrorHandler)[], required, Attached middleware executes when sign-in attempt succeeds. Typically you will redirect the user to your application here.signUp: (express.RouteHandler | express.ErrorHandler)[], required, Attached middleware executes when sign-up attempt succeeds. Typically you will redirect the user to your application here.verify: (express.RouteHandler | express.ErrorHandler)[], Attached middleware executes after the user verifies their email successfully. Typically you will redirect the user to your application here.sendPasswordResetEmail: (express.RouteHandler | express.ErrorHandler)[], Attached middleware executes after the user sends a password reset. Typically you will redirect the user to some success page containing instructions to look for a reset email.resetPassword: (express.RouteHandler | express.ErrorHandler)[], Attached middleware executes after the user successfully resets their password. Typically you will redirect the user to your application here.resendVerificationEmail: (express.RouteHandler | express.ErrorHandler)[], Attached middleware executes after the user resends their email verification email. Typically you will redirect the user to some success page, or if you do not require verification to use your app, you can redirect to your app here.const emailPasswordRouter = auth.createEmailPasswordRouter(
  "/auth/email-password", // Path to mount router at
  "/forgot-password", // Path to your custom reset password UI
  {
    signIn: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/");
      },
    ],
    signUp: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/onboarding");
      },
    ],
    verify: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/");
      },
    ],
    sendPasswordResetEmail: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/email-success");
      },
    ],
    resetPassword: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/email-success");
      },
    ],
    resendVerificationEmail: [
      (req: expressAuth.AuthRequest, res) => {
        res.redirect("/");
      },
    ],
  },
);
app.use(emailPasswordRouter);
// This creates the following routes:
// - POST /auth/email-password/signin
// - POST /auth/email-password/signup
// - GET /auth/email-password/verify
// - POST /auth/email-password/send-password-reset-email
// - POST /auth/email-password/reset-password
// - POST /auth/email-password/resend-verification-email
createOAuthRouterrouterPath: string, required, This is the path relative to the baseUrl given that was configured when creating the ExpressAuth object that this router will be attached to. This is used to build the URL to the callback path configured by the router factory.callback: (express.RouteHandler | express.ErrorHandler)[], required, Once the authentication flow completes, this callback will be called, and you must return a terminating Express route handler here. Typically, you'll redirect to elsewhere in your app based on req.isSignUp.const oAuthRouter = auth.createOAuthRouter("/auth/oauth", {
  callback: [
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  ],
});
app.use(oAuthRouter);
// This creates the following routes:
// - GET /auth/oauth/
// - GET /auth/oauth/callback
routerPath: string, required, This is the path relative to the baseUrl configured when creating the ExpressAuth object. This path is used to build the URL for the callback path configured by the router factory.failureUrl: string, required, URL to redirect to in case of a failure during the Magic Link process.callback: (express.RouteHandler | express.ErrorHandler)[], required, Once the authentication flow completes, this callback will be called, and you must return a terminating Express route handler here. Typically, you'll redirect to elsewhere in your app based on req.isSignUp.send: (express.RouteHandler | express.ErrorHandler)[], this route handler stack will be called when a request is made to send a magic link to a registered email address. Typically, you'll return some HTML or a redirect here that indicates that the user should check their email.signup: (express.RouteHandler | express.ErrorHandler)[], this route handler stack will be called when a request is made to register an email address. Typically, you'll return some HTML or a redirect here that indicates that the user should check their email.const magicLinkRouter = auth.createMagicLinkRouter(
  "/auth/magic-link",
  "/login-failure",
  {
    callback: [
      (req: expressAuth.CallbackRequest, res) => {
        res.redirect("/");
      },
    ],
    send: [
      (req, res) => {
        res.redirect("/check-email.html");
      },
    ],
    signUp: [
      (req, res) => {
        res.redirect("/check-email.html");
      },
    ],
  },
);
app.use(magicLinkRouter);
// This creates the following routes:
// - POST /auth/magic-link/send
// - POST /auth/magic-link/signup
// - GET /auth/magic-link/callback
Unlike the other authentication methods, WebAuthn requires a client-side script that runs in the browser. This script requests JSON from the Gel Auth server that gets options to pass to the Web Authentication API built into the browser, and then after successfully creating new credentials or retrieving existing credentials, it calls back to the endpoints you're configuring below.
In order to facilitate the sign in and sign up ceremonies, we export a helper class called WebAuthnClient that you must configure with some relevant paths based on how you set up your routing below.
import { WebAuthnClient } from "@gel/auth-express";
const webAuthnClient = new WebAuthnClient({
  signupOptionsUrl: "http://localhost:3000/auth/webauthn/signup/options",
  signupUrl: "http://localhost:3000/auth/webauthn/signup",
  signinOptionsUrl: "http://localhost:3000/auth/webauthn/signin/options",
  signinUrl: "http://localhost:3000/auth/webauthn/signin",
  verifyUrl: "http://localhost:3000/auth/webauthn/verify",
});
routerPath: string, required, This is the path relative to the baseUrl configured when creating the ExpressAuth object. This path is used to build the URL for the callback path configured by the router factory.signIn: (express.RouteHandler | express.ErrorHandler)[], required, Attached middleware executes when sign-in attempt succeeds. Typically you will redirect the user to your application here.signUp: (express.RouteHandler | express.ErrorHandler)[], required, Attached middleware executes when sign-up attempt succeeds. Typically you will redirect the user to your application here.verify: (express.RouteHandler | express.ErrorHandler)[], Attached middleware executes after the user verifies their email successfully. Typically you will redirect the user to your application here.signInOptions: (express.RouteHandler | express.ErrorHandler)[], This redirects the user to the appropriate URL of the Gel server to retrieve the WebAuthn sign in options.signUpOptions: (express.RouteHandler | express.ErrorHandler)[], This redirects the user to the appropriate URL of the Gel server to retrieve the WebAuthn sign up options.const webAuthnRouter = auth.createWebAuthnRouter("/auth/webauthn", {
  signInOptions: [],
  signIn: [
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  ],
  signUpOptions: [],
  signUp: [
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/onboarding");
    },
  ],
  verify: [
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  ],
});
app.use(webAuthnRouter);
// This creates the following routes:
// - GET /auth/webauthn/signin/options
// - POST /auth/webauthn/signin
// - GET /auth/webauthn/signup/options
// - POST /auth/webauthn/signup
// - GET /auth/webauthn/verify
Each route is also available as a middleware itself for maximum customization, to allow custom route names, per-route middleware customization, and integration with advanced Express patterns. Here are examples that are equivalent to the ones given in the router factory section:
const builtinRouter = Router()
  .get("/signin", auth.builtin.signIn)
  .get("/signup", auth.builtin.signUp)
  .get(
    "/callback",
    auth.builtin.callback,
    (req: expressAuth.CallbackRequest, res, next) => {
      if (req.isSignUp) {
        return res.redirect("/onboarding");
      }
      res.redirect("/");
    },
  );
app.use("/auth", builtinRouter);
const emailPasswordRouter = Router()
  .post(
    "/signin",
    auth.emailPassword.signIn,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  )
  .post(
    "/signup",
    auth.emailPassword.signUp(
      // URL of the verify endpoint configured below
      "http://localhost:3000/auth/email-password/verify",
    ),
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/onboarding");
    },
  )
  .get(
    "/verify",
    auth.emailPassword.verify,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  )
  .post(
    "/send-password-reset-email",
    auth.emailPassword.sendPasswordResetEmail(
      // URL of the reset password endpoint configured below
      "http://localhost:3000/auth/email-password/reset-password",
    ),
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/email-success");
    },
  )
  .post(
    "/reset-password",
    auth.emailPassword.resetPassword,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/email-success");
    },
  )
  .post(
    "/resend-verification-email",
    auth.emailPassword.resendVerificationEmail,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  );
app.use("/auth/email-password", emailPasswordRouter);
const oAuthRouter = Router()
  .get(
    "/",
    auth.oAuth.redirect(
      // URL of the callback endpoint configured below
      "http://localhost:3000/auth/oauth/callback",
    ),
  )
  .get(
    "/callback",
    auth.oAuth.callback,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  );
app.use("/auth/oauth", oAuthRouter);
const magicLinkRoute = Router()
  .post(
    "/send",
    auth.magicLink.send(
      // URL of the callback endpoint configured below
      "http://localhost:3000/auth/magic-link/callback",
      // URL of the route in your app that should receive login errors
      "/login-failure",
    ),
  )
  .post(
    "/signup",
    auth.magicLink.signUp(
      // URL of the callback endpoint configured below
      "http://localhost:3000/auth/magic-link/callback",
      // URL of the route in your app that should receive login errors
      "/login-failure",
    ),
  )
  .get(
    "/callback",
    auth.magicLink.callback,
    (req: expressAuth.CallbackRequest, res) => {
      // Custom logic after successful authentication
      res.redirect("/");
    },
  );
app.use("/auth/magic-link", router);
const webAuthnRouter = Router()
  .get("/signin/options", auth.webauthn.signInOptions)
  .post(
    "/signin",
    auth.webauthn.signIn,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/");
    },
  )
  .get("/signup/options", auth.webauthn.signUpOptions)
  .post(
    "/signup",
    auth.webauthn.signUp,
    (req: expressAuth.AuthRequest, res) => {
      res.redirect("/onboarding");
    },
  )
  .get("/verify", auth.webauthn.verify, (req: expressAuth.AuthRequest, res) => {
    res.redirect("/");
  });
app.use("/auth/webauthn", webAuthnRouter);
If an error occurs during the authentication flow, it will be passed to the Express error handler. You can use Express error handlers to handle errors either on individual routes by adding the error handlers to the middleware arrays or in your route definitions, or define a router-wide error handler. Any Express error handling pattern is available here, but let's examine a quick example of handling error with the built-in UI flow:
const builtinRouter = auth.createBuiltinRouter({
  callback: [
    (req: expressAuth.CallbackRequest, res, next) => {
      if (req.isSignUp) {
        return res.redirect("/onboarding");
      }
      res.redirect("/");
    },
    (error: any, req, res, next) => {
      res.redirect(`/error?error=${encodeURIComponent(error.message)}`);
    },
  ],
});
createExpressAuth (default package export)baseUrl: string, required, The url of your application; needed for various auth flows (eg. OAuth) to redirect back to.authCookieName?: string, The name of the cookie where the auth token will be stored, defaults to 'gel-session'.pkceVerifierCookieName?: string: The name of the cookie where the verifier for the PKCE flow will be stored, defaults to 'gel-pkce-verifier'passwordResetUrl?: string: The url of the the password reset page; needed if you want to enable password reset emails in your app.Returns: ExpressAuth
ExpressAuthisPasswordResetTokenValid(resetToken: string): Checks if the provided password reset token is valid.getSession(req: ExpressRequest): Returns the session for the specified request.getProvidersInfo(): Returns information about the available providers.createSessionMiddleware(): Creates a session middleware.For the router factories and route middleware, see the sections above for configuring routes for full documentation and usage instructions.
ExpressAuthSessionclient: Client: ext::auth::auth_token global set based on the auth token that is present in the authentication cookie. If there is no cookie, the Client will be the original client that was passed when creating the ExpressAuth object.isSignedIn: () => Promise<boolean>: Checks to see if this Request has a valid, unexpired auth token.TokenDataRepresents the result of successfully completing authentication.
auth_token: string: The raw JWT returned by the server.identity_id: string | null: The UUID of the ext::auth::Identityprovider_token: string | null: If the identity is an OAuth identity, this is the original auth token provided by the Identity Provider.provider_refresh_token: string | null: If the identity is an OAuth identity, this is the original refresh token provided by the Identity Provider, if it was provided by the provider.CallbackRequestThis is an extension of the Express Request interface containing some optional data added by auth callback middleware (either from the built-in UI or in an OAuth callback flow):
req.session?: ExpressAuthSessionreq.tokenData?: TokenDatareq.provider?: ProviderName: The name of the provider type that this authentication event is for.req.isSignUp?: boolean: If this authentication event represents a new user signing up, or an existing user signing in.AuthRequestThis is an extension of the Express Request interface containing some optional data added by the various auth middleware.
session?: ExpressAuthSessiontokenData?: TokenDataFAQs
Helper library to integrate the Gel Auth extension with Express
The npm package @gel/auth-express receives a total of 36 weekly downloads. As such, @gel/auth-express popularity was classified as not popular.
We found that @gel/auth-express demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.