Skip to content

axa-group/oauth2-mock-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

414 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

oauth2-mock-server

npm package Node.js version

OAuth 2 mock server. Intended to be used for development or testing purposes.

When developing an application that exposes or consumes APIs that are secured with an OAuth 2 authorization scheme, a mechanism for issuing access tokens is needed. Frequently, a developer needs to create custom code that fakes the creation of tokens for testing purposes, and these tokens cannot be properly verified, since there is no actual entity issuing those tokens.

The purpose of this package is to provide an easily configurable OAuth 2 server, that can be set up and torn down at will, and can be programmatically run while performing automated tests.

  • Real cryptography. Tokens are signed with actual JWK key pairs. Consuming applications can verify them using the /jwks endpoint, without mocking the verification layer.
  • OIDC-conformant. Exposes all the endpoints a real provider would: discovery, JWKS, authorization code flow with PKCE, userinfo, token introspection, revocation, and end session.
  • Programmatic and CLI. Embed it in a JavaScript or TypeScript test suite (beforeAll/afterAll) or run it as a standalone process for Java, .NET, Python, and other non-JS projects.
  • Per-test customization via event hooks. Use server.service.once(Events.xxx, ...) to alter token claims, simulate errors, or modify responses for a single test — without reconfiguring the server.
  • TypeScript-first. Full type definitions ship with the package. The entire codebase is written in strict TypeScript.

Warning: This tool is not intended to be used as an actual production grade OAuth 2 server. It lacks many features that would be required in a proper implementation.

Requirements

Installation

Add it to your Node.js project as a development dependency:

npm install --save-dev oauth2-mock-server

CLI Usage

The server can be run from the command line.

npx oauth2-mock-server --help

Library Usage

The server and its components can also be leveraged as a library, allowing finer control and configuration.

Here is an example for creating and running a server instance with a single random RSA key:

import { OAuth2Server } from 'oauth2-mock-server';
// ...or in CommonJS style:
// const { OAuth2Server } = require('oauth2-mock-server');

let server = new OAuth2Server();

// Generate a new RSA key and add it to the keystore
await server.issuer.keys.generate('RS256');

// Start the server
await server.start(8080, 'localhost');
console.log('Issuer URL:', server.issuer.url); // -> http://localhost:8080

// Do some work with the server
// ...

// Stop the server
await server.stop();

Any number of existing JSON-formatted keys can be added to the keystore.

// Add an existing JWK key to the keystore
await server.issuer.keys.add({
  kid: 'some-key',
  alg: 'RS256',
  kty: 'RSA',
  // ...
});

JSON Web Tokens (JWT) can also be built programmatically:

import axios from 'axios';

// Build a new token
let token = await server.issuer.buildToken();

// Call a remote API with the token
const response = await axios.get('https://server.example.com/api/endpoint', {
  headers: {
    authorization: `Bearer ${token}`,
  },
});

HTTPS

To support HTTPS, an optional cert and key can be supplied to start the server with SSL/TLS using the in-built NodeJS HTTPS module.

We recommend using a package to create a locally trusted certificate, like mkcert.

let server = new OAuth2Server(
  'test-assets/mock-auth/key.pem',  // Path to private key file
  'test-assets/mock-auth/cert.pem', // Path to public SSL/TLS certificate
);

Note: Enabling HTTPS will also update the issuer URL to reflect the current protocol.

Event Hooks

The library provides a convenient way, through event emitters, to programmatically customize the server processing. This is particularly useful when expecting the OIDC service to behave in a specific way for a single test.

The list of supported events is exported by the library for a guided usage.

import { Events } from 'oauth2-mock-server';
// ...or in CommonJS style:
// const { Events } = require('oauth2-mock-server');
  • Events.BeforeTokenSigning

    Typed signature: (token: MutableToken, req: TokenRequestIncomingMessage) => void

    // Modify the expiration time on next produced token
    server.service.once(Events.BeforeTokenSigning, (token, req) => {
      const timestamp = Math.floor(Date.now() / 1000);
      token.payload.exp = timestamp + 400;
    });
    import basicAuth from 'basic-auth';
    
    // Add the client ID to a token
    server.service.once(Events.BeforeTokenSigning, (token, req) => {
      const credentials = basicAuth(req);
      const clientId = credentials ? credentials.name : req.body.client_id;
      token.payload.client_id = clientId;
    });
  • Events.BeforeResponse

    Typed signature: (tokenEndpointResponse: MutableResponse, req: TokenRequestIncomingMessage) => void

    // Force the oidc service to provide an invalid_grant response
    // on next call to the token endpoint
    server.service.once(Events.BeforeResponse, (tokenEndpointResponse, req) => {
      tokenEndpointResponse.body = {
        error: 'invalid_grant',
      };
      tokenEndpointResponse.statusCode = 400;
    });
  • Events.BeforeUserinfo

    Typed signature: (userInfoResponse: MutableResponse, req: IncomingMessage) => void

    // Force the oidc service to provide an error
    // on next call to userinfo endpoint
    server.service.once(Events.BeforeUserinfo, (userInfoResponse, req) => {
      userInfoResponse.body = {
        error: 'invalid_token',
        error_description: 'token is expired',
      };
      userInfoResponse.statusCode = 401;
    });
  • Events.BeforeRevoke

    Typed signature: (revokeResponse: StatusCodeMutableResponse, req: IncomingMessage) => void

    // Simulates a custom token revocation result code
    server.service.once(Events.BeforeRevoke, (revokeResponse, req) => {
      revokeResponse.statusCode = 418;
    });
  • Events.BeforeAuthorizeRedirect

    Typed signature: (authorizeRedirectUri: MutableRedirectUri, req: IncomingMessage) => void

    // Modify the uri and query parameters
    // before the authorization redirect
    server.service.once(Events.BeforeAuthorizeRedirect, (authorizeRedirectUri, req) => {
      authorizeRedirectUri.url.searchParams.set('foo', 'bar');
    });
  • Events.BeforePostLogoutRedirect

    Typed signature: (postLogoutRedirectUri: MutableRedirectUri, req: IncomingMessage) => void

    // Modify the uri and query parameters
    // before the post_logout_redirect_uri redirect
    server.service.once(Events.BeforePostLogoutRedirect, (postLogoutRedirectUri, req) => {
      postLogoutRedirectUri.url.searchParams.set('foo', 'bar');
    });
  • Events.BeforeIntrospect

    Typed signature: (introspectResponse: MutableResponse, req: IncomingMessage) => void

    // Simulate a custom token introspection response body
    server.service.once(Events.BeforeIntrospect, (introspectResponse, req) => {
      introspectResponse.body = {
        active: true,
        scope: 'read write email',
        client_id: '<client_id>',
        username: 'dummy',
        exp: 1643712575,
      };
    });

Endpoints

Standard endpoints

Endpoint Description
GET /.well-known/openid-configuration Returns the OpenID Provider Configuration Information for the server.
GET /jwks Returns the JSON Web Key Set (JWKS) of all the keys configured in the server.
POST /token Issues access tokens.
GET /authorize Simulates user authentication. Automatically redirects to the callback endpoint. Supports only the code response type.
GET /userinfo Provides extra userinfo claims.
POST /revoke Simulates token revocation. Always returns 200 per RFC 7009.
GET /endsession Simulates the end session endpoint. Redirects to post_logout_redirect_uri; returns state in the redirect URI if provided.
POST /introspect Simulates the token introspection endpoint.

Path overrides

All endpoint paths can be overridden via the endpoints option. Handy when willing to mimic some vendors default configuration. All fields are optional; any omitted path falls back to its default.

const oAuth2Service = new OAuth2Service(oauth2Issuer, {
  // As 'wellKnownDocument' is purposefully omitted, it will be set to its default,
  token: '/oauth/token',
  jwks: '/oauth/jwks',
  authorize: '/oauth/authorize',
  userinfo: '/oauth/userinfo',
  revoke: '/oauth/revoke',
  endSession: '/oauth/logout',
  introspect: '/oauth/introspect',
});

Custom routes

Additional routes can be registered via addRoute(). This may be useful when willing to stub vendor specific management routes, for instance

oAuth2Service.addRoute('POST', '/api/v2/clients', (req, res) => {
  // Your custom implementation goes here
});

Reference

Supported grant types

  • No authentication
  • Client Credentials grant
  • Resource Owner Password Credentials grant
  • Authorization Code grant, with Proof Key for Code Exchange (PKCE) support
  • Refresh token grant
  • JWT Bearer token grant (urn:ietf:params:oauth:grant-type:jwt-bearer)

Supported JWK formats

Crypto scheme kty alg
RSASSA-PKCS1-v1_5 RSA RS256, RS384, RS512
RSASSA-PSS RSA PS256, PS384, PS512
ECDSA EC ES256, ES384, ES512
EdDSA OKP EdDSA, Ed25519

Security

Tokens issued by this server are signed with real cryptographic keys and can be verified by any standard JWT library. However, the server performs no validation of incoming requests — any client ID, secret, username, or password is accepted. This is intentional for testing purposes.

This library is not safe for production use.

Review the Security Policy in SECURITY.md for more details.

Contributing

Contributions are welcome! See CONTRIBUTING.md for setup instructions, coding conventions, and the pull request process.

AI coding agents working in this repository should read AGENTS.md before making any changes.

Attributions

Packages

 
 
 

Contributors