npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@finastra/nestjs-oidc

v0.26.8

Published

<h1> NestJS OIDC Auth module <img src="https://nestjs.com/img/logo-small.svg" height="20" alt="Nest Logo" /> </h1>

Downloads

96

Readme

NestJS module to enable OAuth 2 & OIDC login to your application.
It exposes following endpoints :

  • login?redirect_url redirect_url will be used as the path to redirect to on success login
  • login/callback
  • logout
  • user
  • refresh-token: to request token refresh if the access token is expired. If the token is valid, returns 200.

And also a TokenGuard

Use it

app.module.ts

import { OidcModule } from '@finastra/nestjs-oidc';

@Module({
  imports: [
    OidcModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        issuer: configService.get('OIDC_ISSUER'),
        clientMetadata: {
          client_id: configService.get('OIDC_CLIENT_ID'),
          client_secret: configService.get('OIDC_CLIENT_SECRET'),
        },
        authParams: {
          scope: configService.get('OIDC_SCOPE'),
        },
        origin: configService.get('ORIGIN'),
        // Optional properties
        defaultHttpOptions: {
          timeout: 20000,
        },
        externalIdps: {},
        userInfoCallback: async (userId, idpInfos) => {
          return {
            username: userId,
            customUserInfo: 'custom',
          };
        },
      }),
      inject: [ConfigService],
      imports: [ConfigModule],
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

clientMetadata and authParams are coming from the openid-client library.
defaultHttpOptions can be used to customize all options that openid-client sets for all requests.
externalIdps is an object where keys are a label for the IDP and the value format is described here.
During authentication, the application will authenticate to those identity providers and the identity providers information are then forwarded in userInfoCallback. So that, you're able to call any API with a valid token.
userInfoCallback can be used to customize user information returned in user object on authentication.
postLogoutRedirectUri is used to specify custom endpoint to redirect to after logout (default is /login).
userInfoMapping can be used to map different claims to user id and and user name (defaults mappings are here).

Example with externalIdps

In this example, I want to authenticate to an external IDP to be able to request an API to get my user groups.
Here is the sample of config to add:

{
  externalIdps: {
    azure: {
      clientId: configService.get('OIDC_AAD_CLIENT_ID'),
      clientSecret: configService.get('OIDC_AAD_CLIENT_SECRET'),
      issuer: configService.get('OIDC_AAD_ISSUER'),
      scope: configService.get('OIDC_SCOPE'),
    },
  },
  userInfoCallback: async (userId, idpInfos) => {
    const accessToken = idpInfos['azure'].accessToken;
    const groups = (
      await axios.request({
        method: 'get',
        url: `URL/${userId}/memberOf`,
        headers: {
          authorization: `Bearer ${accessToken}`,
        },
      })
    ).data.value.map(group => group.id);
    return {
      id: userId,
      groups,
    };
  },
}

main.ts

import { setupSession } from '@finastra/nestjs-oidc';

setupSession(app, 'name-of-cookie');

By default, session secret will be looked for in the SESSION_SECRET environment variable. If not provided, a uuid will be generated instead

Auth Guards

Only one guard is exposed.
You can either use it globally, or scoped per controller or route.

Globally

main.ts

app.useGlobalGuards(app.get(TokenGuard));

Using the token guard globally will protect all your routes.

If you want to redirect all the unauthorized requests to the login route, you need to add this middleware in your project:

import { LOGIN_SESSION_COOKIE } from '@finastra/nestjs-oidc';
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Response } from 'express';

@Injectable()
export class StaticMiddleware implements NestMiddleware {
  use(req: any, res: Response, next: Function) {
    // If the request is authenticated, do nothing
    if (req.isAuthenticated()) {
      return next();
    }

    // Add the LOGIN_SESSION_COOKIE to make sure to prompt the login page if the user has already authenticated before
    res.cookie(LOGIN_SESSION_COOKIE, 'logging in', {
      maxAge: 15 * 1000 * 60,
    });

    // If you want to send the query params to the login middleware
    const searchParams = new URLSearchParams(req.query);

    // If you're using the multitenancy authentication, you'll need to get the prefix
    const channelType = req.params.channelType;
    const tenantId = req.params.tenantId;
    const prefix = `${tenantId}/${channelType}`;

    // Redirect to login page and forward the request query params, after logging in, redirect to the redirect_url parameter
    res.redirect(`/${prefix}/login?redirect_url=${req.url}&${searchParams.toString()}`);
  }
}

Controller or route based

*.controller.ts

import { TokenGuard } from '@finastra/nestjs-oidc';

@UseGuards(TokenGuard)
@Controller('')

Popup login

Per default the login middleware will use the request header sec-fetch-dest value to know if the login should be done it a popup or not. If the value is set to iframe this will cause most browsers to show a popup to enter credentials on unauthorized responses. After login success it close the popup and redirect the page initiator as for a normal login flow.

Other options to register OidcModule

| Option | Description | | ----------------- | ----------------------------------------------------------------------- | | redirectUriLogout | Where to redirect user after logout. If not specified, origin is used | | usePKCE | Boolean to user or not PKCE | | userInfoMethod | token or endpoint. Default being token |

Authenticating with multi-tenancy

Pre-requisites

Before you begin, this multi-tenancy implementation is only compatible with FFDC tenants. Make sure you've configured your applications and tenants in Finastra developer portal and Finastra Organization Admin portal.

Exposed endpoints

The exposed endpoints are the same but they will be prefixed by tenantId and channelType (/:tenantId/:channelType/):

  • login
  • login/callback
  • logout
  • user
  • refresh-token

The TokenGuard is available and works the same as in single tenancy.

If your application handles single and multi tenancy, you can use @isAvailableRouteForMultitenant decorator with a boolean parameter on classes or functions.

Usage

app.module.ts

import { OidcModule } from '@finastra/nestjs-oidc';

@Module({
  imports: [
    OidcModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        issuerOrigin: configService.get('OIDC_ISSUER_ORIGIN'),
        b2c: {
          clientMetadata: {
            client_id: configService.get('OIDC_CLIENT_ID_B2C'),
            client_secret: configService.get('OIDC_CLIENT_SECRET_B2C'),
          },
        },
        b2e: {
          clientMetadata: {
            client_id: configService.get('OIDC_CLIENT_ID_B2E'),
            client_secret: configService.get('OIDC_CLIENT_SECRET_B2E'),
          },
        },
        authParams: {
          scope: configService.get('OIDC_SCOPE'),
        },
        origin: configService.get('ORIGIN'),
        // Optional properties
        defaultHttpOptions: {
          timeout: 20000,
        },
        userInfoCallback: async (userId, idpInfos) => {
          return {
            username: userId,
            customUserInfo: 'custom',
          };
        },
      }),
      inject: [ConfigService],
      imports: [ConfigModule],
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

issuerOrigin is the route url of the IDP issuer. Issuer will be built with this pattern: :issuerOrigin/:tenantId/.well-known/openid-configuration The other parameters remains the same that on single tenancy except that clientMetadata need to be embedded in channel type b2c or b2e parameter.

Utils

Setup Session

If you don't want to have to think about how to configure the session, you can use our helpers. We currently expose 2: in-memory and mongoDB.
The configuration for those can be found here.

In Memory

This will not work if you're deploying multiple instances of your application.

import { sessionInMemory } from '@finastra/nestjs-oidc/utils/session';

sessionInMemory(app, 'test-app');

// Alternative way
import { setupSession } from '@finastra/nestjs-oidc';

setupSession(app, 'test-app');

MongoDB

Preferred method if you're deploying multiple instances of your application.

import { sessionMongo } from '@finastra/nestjs-oidc/utils/session';

// Use mongoDB as session store
sessionMongo(app, 'test-app', {
  mongoUrl: 'mongodb://user:password@localhost:27017',
  dbName: 'sample-db',
});

Third parameter is directly being passed to connect-mongo. Refer to its documentation for more information.