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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ndwnu/auth

v3.0.0

Published

This package provides some tools to ease the implementation of authentication in Angular applications and uses [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc/tree/master) under the hood. It aims to simplify and improve developm

Readme

@ndwnu/auth

This package provides some tools to ease the implementation of authentication in Angular applications and uses angular-oauth2-oidc under the hood. It aims to simplify and improve development by offering a service, multiple guards and an easy installation process for your new or existing Angular applications.

Features

  • 🚀 One config installation, by utilizing a custom EnvironmentProviders and the Angular Injection Context we can simplify the installation process and avoid the need of manually configuring the OAuth process.
  • 🛡️ CanActivate Guard, we provide a guard to cover most of the use cases, including:
    • Force a login
    • Role based access
    • Custom callback function to handle unauthorized access
  • 🔐 NdwAuthService: A service that provides a simple interface to interact with the OAuth process, including login, logout, and different observables like a user profile.
  • ☎️ Default onUnauthorized (optional) for all the AuthGuards, define once and it is used automatically in all the guards.

Before you start

This package uses the standalone APIs which are introduced in Angular 14. You can migrate your project easily using the schematic provided by Angular. Start migrating your project: https://angular.dev/reference/migrations/standalone

Installation

  npm install @ndwnu/auth

Usage

After installing the package, you can use provideNdwAuth to configure authentication in your application. This provider will automatically configure OAuth and initializes it using the provideAppInitializer.

Basic usage

To use the provideNdwAuth provider, you need to import it in your app.config.ts file and provide it in the providers array.

// app.config.ts
import { provideNdwAuth } from '@ndwnu/auth';

export const appConfig: ApplicationConfig = {
  providers: [
    provideNdwAuth({
      authConfig: {
        issuer: 'https://iam.test.com/auth/realms/my-realm',
        redirectUri: window.location.origin,
        postLogoutRedirectUri: window.location.origin,
        clientId: 'app-client-id',
        responseType: 'code',
        scope: 'openid profile email roles',
        showDebugInformation: false,
      },
      moduleConfig: {
        resourceServer: {
          allowedUrls: ['http://localhost:4200'],
          sendAccessToken: true,
        },
      },
    }),
    provideHttpClient(withInterceptorsFromDi()), // optional
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
  ],
};

// main.ts
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));

onUnauthorized

The onUnauthorized function is called when the user is not authenticated or does not have the required roles. You can use this function to redirect the user to a login page or show an error message. It runs in the injection context so you can inject your own services. The callback function receives a parameter of type UnauthorizedType which can be either forbidden or unauthenticated. Forbidden means that the user is authenticated but does not have the required roles, while unauthenticated means that the user is not authenticated.

Defining the onUnauthorized callback function is optional, but it is recommended to define one to handle unauthorized access in a consistent way across your application. You can still override the onUnauthorized function in the guards if you want to handle it differently in a specific route.

import { NdwAuthService, UnauthorizedType } from '@ndwnu/auth';
import { Router } from '@angular/router';

export const appConfig: ApplicationConfig = {
  providers: [
    provideNdwAuth({
      ...,
      onUnauthorized: (type) => {
        if (type === 'forbidden') {
          window.alert('You do not have permission to access this page.');
        } else if (type === 'unauthenticated') {
          window.alert('You are not authenticated. Please log in.');
          inject(Router).navigate(['/login']);
        }
      },
    }),
  ],
};

Custom Storage

You can also use a custom storage implementation by providing a new provideNdwAuthStorage provider. This will overwrite the default storage implementation. By default this implementation uses localStorage, but you can use any storage implementation that implements the OAuthStorage interface.

import { provideNdwAuth } from '@ndwnu/auth';

export const appConfig: ApplicationConfig = {
  providers: [
    provideNdwAuth({ ... }),
    provideNdwAuthStorage({
      factory: () => {
        return new CustomStorage();
      },
      deps: [] // Optional, you can provide dependencies here
    }),
  ]
};

Using Interceptors

We currently do not provide the interceptors by default, but you can use the withInterceptorsFromDi function to add the interceptors to your application. We do this because we want to avoid duplicating the HttpClient providers, as it causes an issue known as 'provider shadowing'.

In Angular's dependency injection system:

  • The last registered provider wins
  • The providers are processed in order

This means that either:

  • Your custom HTTP client configuration in appConfig will override the one provided by provideNdwAuth
  • Or provideNdwAuth's HTTP client will override yours, depending on the order of registration

This could lead to:

  • Missing interceptors if they're registered in only one of the providers
  • Unexpected behavior where some services use one HTTP client and others use another

Example on how to use:

import { provideNdwAuth } from '@ndwnu/auth';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideNdwAuth({ ... }),
    provideHttpClient(withInterceptorsFromDi()),
  ]
};

NdwAuthService

You can use the NdwAuthService to login and logout the user, check roles and to get the user profile.

Login and logout

import { NdwAuthService } from '@ndwnu/auth';
import { Component, inject } from '@angular/core';

@Component({
  selector: 'app-login',
  template: `
    <button (click)="login()">Login</button>
    <button (click)="logout()">Logout</button>
  `,
})
export class LoginComponent {
  readonly #ndwAuthService = inject(NdwAuthService);

  login() {
    this.#ndwAuthService.login();
  }

  logout() {
    this.#ndwAuthService.logout();
  }
}

Checking roles

You can use the hasRole method to check if the user has a specific role.

import { NdwAuthService } from '@ndwnu/auth';
// ...
readonly #ndwAuthService = inject(NdwAuthService);
// ...
if (this.#ndwAuthService.hasRoles(['admin'])) {
  // User has the admin role
} else {
  // User does not have the admin role
}

You can also check if the user has all the required roles or if the user has at least one of the required roles.

this.#ndwAuthService.hasRoles(['admin', 'editor'], 'all'); // Default, User needs to have both 'admin' and 'editor' roles
this.#ndwAuthService.hasRoles(['admin', 'writer'], 'any'); // User needs to have at least one of the provided roles

User profile

You can use the userProfile$ observable to get the user profile. This observable will emit the user profile when the user is authenticated and will emit null when the user is not authenticated.

import { NdwAuthService } from '@ndwnu/auth';
import { Component, inject } from '@angular/core';

@Component({
  selector: 'app-user-profile',
  template: `
    @let userProfile = ndwAuthService.userProfile$ | async;
    @if (userProfile) {
      <p>Logged in as {{ userProfile.name }}</p>
    } @else {
      <p>Not logged in</p>
    }
  `,
})
export class UserProfileComponent {
  readonly ndwAuthService = inject(NdwAuthService);
}

Observables: isAuthenticated$, isDoneLoading$ & isDoneAuthenticating$

You might need to check if the user is authenticated or if the authentication process is done loading. You can use the isAuthenticated$ and isDoneLoading$ observables to do this.

import { NdwAuthService } from '@ndwnu/auth';
// ...
readonly #ndwAuthService = inject(NdwAuthService);
// ...
this.#ndwAuthService.isAuthenticated$.subscribe((isAuthenticated) => {
  if (isAuthenticated) {
    // User is authenticated
  }
});
// ...
this.#ndwAuthService.isDoneLoading$.subscribe((isDoneLoading) => {
  if (isDoneLoading) {
    // The authentication process is done loading
  }
});
// Use this observable to check if the authentication process is done loading
this.#ndwAuthService.isDoneAuthenticating$.subscribe((isDone) => {
  if (isDone) {
    // User is authenticated & the authentication process is done loading
  }
});

Guards

You can use the ndwAuthGuard guard to protect your routes. This guard will check if the user is authenticated and will trigger functionality based on your config. However you can still create your own Guards to protect your routes, but you will need to implement the logic yourself.

The guard has the following options:

  • forceLogin: A boolean that indicates if the user should be forced to the OAuth login if not authenticated. The default is true.
  • onUnauthorized: This is a callback function that will be called when the user is not authenticated or does not have the required roles. You can use this function to redirect the user to a login page or show an error message. This overrides the default onUnauthorized function provided by provideNdwAuth.
  • roles': An array of roles that the user must have to access the route. This is optional, but if you provide it, the guard will check if the user has the required roles.
  • checkRoles: Options are 'all', 'any', This will check if the user has all the required roles or at least one of the required roles. The default is 'all'.

onUnauthorized

The onUnauthorized function is called when the user is not authenticated or does not have the required roles. You can use this function to redirect the user to a login page or show an error message. It runs in the injection context so you can inject your own services. The callback function receives a parameter of type UnauthorizedType which can be either forbidden or unauthorized. Forbidden means that the user is authenticated but does not have the required roles, while unauthenticated means that the user is not authenticated.

The onAuthorized function in the guard will override the default onUnauthorized function provided by provideNdwAuth for the specific route.

ndwAuthGuard

import { ndwAuthGuard, NdwAuthService, UnauthorizedState } from '@ndwnu/auth';
import { Router } from '@angular/router';

export const routes: Routes = [
  {
    path: 'admin',
    loadComponent: () => import('./features/admin/admin.component').then((m) => m.AdminComponent),
    canActivate: [
      ndwAuthGuard({
        forceLogin: true, // Forces the user to login if not authenticated
        roles: ['admin', 'manager'], // The roles required to access the route
        checkRoles: 'any', // The user must have at least one of the required roles
        onUnauthorized: (type: UnauthorizedState) => {
          if (type === 'forbidden') {
            window.alert('You do not have permission to access this page.');
            inject(Router).navigate(['/public']);
          } else if (type === 'unauthenticated') {
            window.alert('You are not authenticated. Please log in.');
            inject(NdwAuthService).login();
          }
        },
      }),
    ],
  },
];

Create a reusable guard

You can create a reusable guard by using the ndwAuthGuard function and passing it to the canActivate property of your route.

import { NdwAuthService, ndwAuthGuard } from '@ndwnu/auth';

const myDefaultGuard = ndwAuthGuard({
  forceLogin: true,
  onUnauthorized: () => {
    window.alert('You are not authorized to access this page. Please log in.');
    inject(NdwAuthService).logout();
  },
});

const routes = [
  {
    path: 'admin',
    loadComponent: () => import('./features/admin/admin.component').then((m) => m.AdminComponent),
    canActivate: [myDefaultGuard],
  },
  {
    path: 'secret-page',
    loadComponent: () =>
      import('./features/secret/secret.component').then((m) => m.SecretComponent),
    canActivate: [myDefaultGuard],
  },
];