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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@amaurylapaque/angular-auth

v1.0.1

Published

Pluggable Angular authentication layer with adapters for OIDC, MSAL, Firebase, Supabase, JWT and Mock providers.

Readme

@amaurylapaque/angular-auth

npm version npm downloads license

Pluggable Angular authentication layer. One AuthService façade, one authGuard, one authInterceptor — switch the underlying provider (OIDC, MSAL, Firebase, Supabase, JWT, Mock) by changing a single line in your bootstrap.

Live demo: https://angular-auth-demo.vercel.app/ — try the live adapter switcher and browse the in-app docs.

Documentation:

Why

Angular apps tend to couple to whichever auth SDK was picked on day one. When the team wants to migrate from, say, Keycloak to Auth0, or support both during a transition, every component that reads user$ or getAccessToken() needs to change. This package puts a thin, stable contract in front of the SDK so the rest of the app never has to know.

Install

npm install @amaurylapaque/angular-auth

# then install only the SDK(s) for the adapter(s) you actually use
npm install angular-auth-oidc-client         # for OIDC (Auth0, Keycloak, Okta, Cognito, ...)
npm install @azure/msal-browser @azure/msal-angular   # for MSAL
npm install firebase                         # for Firebase
npm install @supabase/supabase-js            # for Supabase
# JWT and Mock adapters have no extra peer deps

Core concept

┌─────────────────────────────────────────┐
│  Your components / services / guards    │
│     inject(AuthService)                 │
└──────────────────┬──────────────────────┘
                   │   unified contract
                   ▼
            ┌──────────────┐
            │ AuthProvider │  interface
            └──────┬───────┘
      ┌───────┬────┴─────┬──────────┬─────────┬────────┐
      ▼       ▼          ▼          ▼         ▼        ▼
    OIDC    MSAL     Firebase   Supabase    JWT      Mock

Components only ever touch AuthService. Swapping the provider is a single-file change in the app bootstrap.

Bootstrap

provideAuth(<adapter>, <config>) installs everything:

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import {
  provideAuth,
  provideOidc,
  authInterceptor,
} from '@amaurylapaque/angular-auth';

import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptors([authInterceptor])),
    provideAuth(
      provideOidc({
        authority: 'https://your-tenant.auth0.com',
        clientId: 'abc123',
        redirectUrl: window.location.origin,
      }),
      {
        protectedResourceUrls: ['https://api.example.com'],
      },
    ),
  ],
});

Using it in a component

import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { AuthService } from '@amaurylapaque/angular-auth';

@Component({
  standalone: true,
  imports: [AsyncPipe],
  template: `
    @if (auth.isAuthenticated()) {
      <p>Hello {{ auth.user()?.name }}</p>
      <button (click)="auth.logout()">Logout</button>
    } @else {
      <button (click)="auth.login()">Login</button>
    }
  `,
})
export class HeaderComponent {
  readonly auth = inject(AuthService);
}

Route protection

// app.routes.ts
import { Routes } from '@angular/router';
import { authGuard } from '@amaurylapaque/angular-auth';

export const routes: Routes = [
  { path: 'private', loadComponent: () => import('./private.component'), canActivate: [authGuard] },
];

Adapters

1. OIDC — Auth0, Keycloak, Okta, Cognito, Zitadel, Authentik, ...

Any spec-compliant OpenID Connect issuer.

provideAuth(
  provideOidc({
    authority: 'https://your-tenant.auth0.com',    // Auth0
    // authority: 'https://keycloak/realms/my-app', // Keycloak
    // authority: 'https://cognito-idp.<region>.amazonaws.com/<pool>', // Cognito
    clientId: 'abc123',
    redirectUrl: window.location.origin,
    scope: 'openid profile email offline_access',
  }),
);

2. MSAL — Azure AD / Entra ID

provideAuth(
  provideMsal({
    clientId: '00000000-0000-0000-0000-000000000000',
    authority: 'https://login.microsoftonline.com/<tenant-id>',
    redirectUri: window.location.origin,
    scopes: ['User.Read'],
    interactionType: 'redirect', // or 'popup'
  }),
);

3. Firebase

import { GoogleAuthProvider } from 'firebase/auth';

provideAuth(
  provideFirebase({
    firebaseOptions: {
      apiKey: '...',
      authDomain: '...',
      projectId: '...',
    },
    defaultStrategy: { type: 'popup', provider: new GoogleAuthProvider() },
  }),
);

Email-password, custom token and anonymous login are all supported — pick a strategy at config time or pass it per call via login({ extra: { strategy: {...} } }).

4. Supabase

provideAuth(
  provideSupabase({
    url: 'https://xyz.supabase.co',
    anonKey: '...',
    defaultStrategy: { type: 'password', email: '[email protected]', password: 'secret' },
    // or { type: 'oauth', provider: 'github' }
    // or { type: 'otp', email: '[email protected]' }  (magic link)
  }),
);

The adapter wraps @supabase/supabase-js — OAuth providers (github, google, discord…), password, OTP and session refresh all go through the unified AuthService.

5. JWT — custom backend

provideAuth(
  provideJwt({
    loginUrl: 'https://api.example.com/auth/login',
    refreshUrl: 'https://api.example.com/auth/refresh',
    logoutUrl: 'https://api.example.com/auth/logout',
    storage: 'local',
  }),
);

// usage:
auth.login({ extra: { email: '[email protected]', password: 'secret' } });

mapLoginResponse and mapUser let you adapt any backend shape without changing the call sites.

6. Mock — dev & tests

provideAuth(
  provideMock({
    startAuthenticated: true,
    user: { id: 'u1', name: 'Alice', email: '[email protected]', roles: ['admin'] },
  }),
);

Injecting MockAuthAdapter in a test gives you setUser(user | null) for flipping state synchronously between scenarios.

Switching providers in practice

In most teams the choice is an environment concern, not a code concern:

// bootstrap helper
import { environment } from './environments/environment';

function authFeature() {
  switch (environment.auth.kind) {
    case 'oidc':     return provideOidc(environment.auth.config);
    case 'msal':     return provideMsal(environment.auth.config);
    case 'firebase': return provideFirebase(environment.auth.config);
    case 'supabase': return provideSupabase(environment.auth.config);
    case 'jwt':      return provideJwt(environment.auth.config);
    case 'mock':     return provideMock(environment.auth.config);
  }
}

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptors([authInterceptor])),
    provideAuth(authFeature()),
  ],
});

Writing your own adapter

Implement AuthProvider, expose a provideXxx() that wires it behind the AUTH_PROVIDER token:

@Injectable()
class MyAdapter implements AuthProvider {
  readonly user$ = /* ... */;
  readonly isAuthenticated$ = /* ... */;
  readonly isLoading$ = /* ... */;
  init(): Promise<void> { /* ... */ }
  login(): Promise<void> { /* ... */ }
  logout(): Promise<void> { /* ... */ }
  getAccessToken(): Promise<string | null> { /* ... */ }
}

export function provideMyAdapter(config: MyConfig): AuthAdapterFeature {
  return {
    providers: [
      { provide: MY_CONFIG, useValue: config },
      MyAdapter,
      { provide: AUTH_PROVIDER, useExisting: MyAdapter },
    ],
  };
}

Running the demo

A minimal standalone Angular app lives under demo/. It boots with the Mock adapter so it runs offline with no credentials — switching providers is a single line in demo/src/app/app.config.ts. The demo also ships with a live adapter switcher in the UI (backed by localStorage + reload) showing how different Mock configurations behave with the exact same components.

npm install
npm run demo         # ng serve demo → http://localhost:4200
npm run demo:build   # production build into dist/demo

Running the test suite

npm test             # Vitest + @analogjs/vitest-angular, jsdom
npm run test:watch

Current coverage (42 specs): every adapter has its own spec with the upstream SDK mocked via vi.mockMockAuthAdapter, JwtAuthAdapter (login / refresh / expiry / storage / custom response mapping), OidcAuthAdapter (Keycloak + Cognito claim shapes), MsalAuthAdapter (event subjects, redirect vs popup, silent token), FirebaseAuthAdapter (auth state, strategies, id token), SupabaseAuthAdapter (session hydration, onAuthStateChange, password / OAuth / OTP strategies, refresh). Plus AuthService façade and authInterceptor matching rules.

Security

Full details in SECURITY.md. Quick summary for integrators:

  • Never use protectedResourceUrls: ['*'] in production. It leaks your users' tokens to every domain you call — including third-party APIs, CDNs and analytics. Always list your own API origins explicitly.
  • localStorage is readable by any script on your origin. A single XSS vulnerability exfiltrates every stored token. The JWT adapter defaults to local for DX; switch to storage: 'session' (per-tab) or storage: 'memory' (no persistence) for high-sensitivity apps, or move auth to HttpOnly server cookies.
  • Register redirect URIs strictly at your identity provider. Never accept open redirects.
  • Review npm audit output before every release. CI runs it automatically via .github/workflows/ci.yml.
  • Report vulnerabilities privately via the GitHub security advisory link in SECURITY.md — never in a public issue.

What's out of scope (for now)

  • SAML / CAS — protocol support belongs in a separate adapter
  • Passkeys / WebAuthn — planned, but spec is still shifting
  • Server-side session renewal strategies — each adapter uses its SDK's defaults