Getting Started
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.
- Install the package
- Implement Entities
- Implement Repositories
- Set up the AuthorizationServer with desired grant types
- Implement the Endpoints
Installation
Choose your preferred package manager to install @jmondi/oauth2-server:
- pnpm
- npm
- yarn
- jsr
- deno
- bun
pnpm add @jmondi/oauth2-server
npm install --save @jmondi/oauth2-server
yarn add @jmondi/oauth2-server
npx jsr add @jmondi/oauth2-server
deno add @jmondi/oauth2-server
bunx jsr 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
- Use HTTPS for all OAuth2 endpoints
- Implement rate limiting to prevent brute force attacks
- Use strong, unique client secrets for each client
- Implement proper token storage and transmission practices
- Regularly rotate secrets and tokens