Skip to main content

Getting Started

JSR GitHub package.json version GitHub Workflow Status Test Coverage NPM Downloads

Introduction

A standards compliant implementation of an OAuth 2.0 authorization server for Nodejs that utilizes JWT and Proof Key for Code Exchange (PKCE), written in TypeScript.

Quick Start

This section provides a high-level overview of setting up the OAuth2 server.

  1. Install the package
  2. Implement Entities
  3. Implement Repositories
  4. Set up the AuthorizationServer with desired grant types
  5. Implement the Endpoints

Installation

Choose your preferred package manager to install @jmondi/oauth2-server:

pnpm add @jmondi/oauth2-server

Implement Entities

You are going to need to setup the entities that the OAuth2 server uses to store data. See the full list of entities.

Implement Repositories

Next you need to implement the repositories that the OAuth2 server uses to interact with the entities. See the full list of repositories.

Setup the Authorization Server

The AuthorizationServer is the core component of the OAuth2 implementation. It requires repositories for managing clients, access tokens, and scopes. Grant types are opt-in and must be explicitly enabled.

const authorizationServer = new AuthorizationServer(
clientRepository,
accessTokenRepository,
scopeRepository,
"secret-key",
);
authorizationServer.enableGrantType("client_credentials");
// other grant types you want to enable

For a complete list of configuration options, refer to the configuration documentation.

Endpoints

Token Endpoint

The /token endpoint is a back-channel endpoint that issues access tokens.

app.post("/token", async (req: Express.Request, res: Express.Response) => {
try {
const oauthResponse = await authorizationServer.respondToAccessTokenRequest(req);
return handleExpressResponse(res, oauthResponse);
} catch (e) {
handleExpressError(e, res);
}
});

Authorize Endpoint

The /authorize endpoint is a front-channel endpoint that issues authorization codes, which can be exchanged for access tokens.

import { requestFromExpress } from "@jmondi/oauth2-server/express";

app.get("/authorize", async (req: Express.Request, res: Express.Response) => {
try {
// Step 1: Validate the authorization request
const authRequest = await authorizationServer.validateAuthorizationRequest(
request,
requestFromExpress(req),
);

// Step 2: Ensure user is authenticated
if (!req.user) {
return res.redirect("/login"); // Redirect to login if user is not authenticated
}

// Step 3: Set the authenticated user on the AuthorizationRequest
authRequest.user = req.user;

// Step 4: Check if the user has approved the authorization
authRequest.isAuthorizationApproved = getIsAuthorizationApprovedFromSession();

// Step 5: If not approved, redirect to approval screen
if (!authRequest.isAuthorizationApproved) {
return res.redirect("/scopes"); // Redirect to scope approval screen
}

// Step 6: Complete the authorization request
const oauthResponse = await authorizationServer.completeAuthorizationRequest(authRequest);
return handleExpressResponse(res, oauthResponse);
} catch (e) {
handleExpressError(e, res);
}
});

Revoke Token Endpoint

The /token/revoke endpoint revokes an existing token.

app.post("/token/revoke", async (req: Express.Request, res: Express.Response) => {
try {
const oauthResponse = await authorizationServer.revoke(req);
return handleExpressResponse(res, oauthResponse);
} catch (e) {
handleExpressError(e, res);
}
});

Security Best Practices

  1. Use HTTPS for all OAuth2 endpoints
  2. Implement rate limiting to prevent brute force attacks
  3. Use strong, unique client secrets for each client
  4. Implement proper token storage and transmission practices
  5. Regularly rotate secrets and tokens