For the full Express Library Reference, click here.

Quick example

The following example creates a route which can only be accessed from logged-in users.

const propelAuth = require("@propelauth/express");
const { requireUser } = propelAuth.initAuth({
  // You can find your Auth URL and API key under the Backend Integration
  //   section for your project at https://app.propelauth.com.
  authUrl: "YOUR_AUTH_URL",
  apiKey: "YOUR_API_KEY",
});

// requireUser is a middleware which validates the access token
app.get("/hello", requireUser, (req, res) => {
  res.text("Hello user with ID " + req.user.userId);
});

How it works

For a detailed description of what’s going on under the hood, see here.

Installation

In your Express app, install the @propelauth/express library.

$ npm install --save @propelauth/express

Initialize

initAuth performs a one-time initialization of the library. It will verify your apiKey is correct and fetch the metadata needed to verify access tokens in requireUser, optionalUser, or requireOrgMember.

We recommend calling this in a new file and exporting the result.

// propelauth.js
const propelAuth = require("@propelauth/express");
module.exports = propelAuth.initAuth({
  // If true, error messages returned to the user will be detailed.
  // It's useful for debugging, but a good idea to turn off in production.
  debugMode: true,
  // You can find your Auth URL and API key under the Backend Integration
  //   section for your project at https://app.propelauth.com.
  authUrl: "https://auth.yourdomain.com",
  apiKey: "YOUR_API_KEY",
});

And then importing just what you need:

const { requireUser } = require("./propelauth");

Protect API routes

requireUser

An Express middleware that will verify the request was made by a valid user. Specifically, it will:

  1. Check that a valid access token was provided. If not, the request is rejected with a 401 status code.
  2. Set user on the Request with the user’s information.
app.get("/hello", requireUser, (req, res) => {
  res.text("Hello user with ID " + req.user.userId);
});

The user object looks like:

PropertyDescription
userIdThe id of the user
orgIdToOrgMemberInfoA dictionary of org ids to metadata about the org. Includes all orgs that the user is in
legacyUserIdThe original ID of the user, if the user was migrated from an external source

The values of orgIdToOrgMemberInfo are OrgMemberInfo’s, with the following fields/functions:

FieldDescription
orgIdThe id of the org
orgNameThe name of the org
urlSafeOrgNameA URL-safe version of the name of the org
assignedRole(): stringThe user’s role within the organization. See Roles and Permissions for more details.
permissions(): string[]The user’s permissions within the organization. See Roles and Permissions
isRole(role: string): booleanReturns True if the user’s role within the organization matches the role passed in
isAtLeastRole(role: string): booleanReturns True if the user’s role within the organization is at least the role passed in. If the hierarchy of roles is Owner => Admin => Member, specifying “Admin” will return True for Admins and Owners, but False for Members.
hasPermission(permission: string): booleanReturns True if the user has a specific permission. The users’ permissions are derived from their role within this organization.
hasAllPermissions(permissions: string[]): booleanReturns True if the user has all the specified permissions. The users’ permissions are derived from their role within this organization.

optionalUser

Similar to requireUser, except if an access token is missing or invalid, the request is allowed to continue, but user on the Request will be undefined.

app.get("/hello", optionalUser, (req, res) => {
  if (req.user) {
    res.text("Hello user with ID " + req.user.userId);
  } else {
    res.text("Hello anonymous");
  }
});

requireOrgMember

An Express middleware that will verify the request was made by a valid user that belongs to a specific organization.

// By default, requireOrgMember checks for orgId as a path parameter
app.get("/org/:orgId/hello", requireOrgMember(), (req, res) => {
  res.text("You are in " + req.org.orgName);
});

Specifically, it will:

  1. Check that a valid access token was provided. If not, the request is rejected with a 401 status code.
  2. Set user on the Request with the user’s information. See requireUser for what the user object looks like.
  3. Find an id for an organization within the request. By default, it will check Request.params.orgId (a path parameter named orgId).
  4. Check that the user is a member of that organization. If not, the request is rejected with a 403 status code.
  5. Set org on the Request with the organization’s information for this user.

Roles and Permissions

A user has a Role within an organization. By default, the available roles are Owner, Admin, or Member, but these can be configured. These roles are also hierarchical, so Owner > Admin > Member.

Roles allow you to control what different users can do within your product. If you want to check a user’s role, you can use requireOrgMemberWithExactRole or requireOrgMemberWithMinimumRole.

// Assuming a Role structure of Owner => Admin => Member

app.get(
  "/org/:orgId/admin",
  requireOrgMemberWithExactRole({ role: "Admin" }),
  (req, res) => {
    res.text("You are an Admin of " + req.org.orgName);
  }
);

app.get(
  "/org/:orgId/admin_or_owner",
  requireOrgMemberWithMinimumRole({ minimumRequiredRole: "Admin" }),
  (req, res) => {
    res.text("You are an Admin of " + req.org.orgName);
  }
);

Permissions are arbitrary strings associated with a role. For example, can_view_billing, ProductA::CanCreate, and ReadOnly are all valid permissions. The PropelAuth dashboard allows you to set up these permissions.

You can use requireOrgMemberWithPermission or requireOrgMemberWithAllPermissions to check for a given permission.

app.get(
  "/org/:orgId/billing",
  requireOrgMemberWithPermission({ permission: "can_view_billing" }),
  (req, res) => {
    // TODO: view billing
  }
);

All of these functions, just like requireOrgMember, can also take in orgIdExtractor, and will set both req.user and req.org on a valid request.

API calls

In addition to protecting API routes, you can make requests to PropelAuth to fetch more information about your users or organizations. You can also create new users, update user metadata, and more.

// Example
const usersResponse = await fetchUsersByQuery({
  emailOrUsername: "@example.com",
  orderBy: "LAST_ACTIVE_AT_DESC",
});
for (const user of userResponse.users) {
  console.log("Found user " + user);
}

See Express Library Reference for more information on available functionality.

Next Steps

Done with your backend? Next you can deploy to production.