ngx-auth-client
A reactive authentication layer for Angular — auth state as signals, route protection via a functional guard, zero identity-provider imports in feature code.
Duration
Aug 2026 – Present
Contributors
1 contributor
Technologies
9+ tech
Project Overview
Angular is signals-first and zoneless by default, but keycloak-angular still exposes authentication as plain getters — keycloak.authenticated, keycloak.token — with only an event signal to tell you something changed. In a zoneless application a getter read in a template simply never triggers change detection; Zone.js used to paper over that, and without it the state is invisible. ngx-auth-client writes the derivation layer once: AuthService exposes authenticated, claims, and roles as signals that update on login, logout, and refresh. A functional authGuard protects routes with role requirements that accumulate down the route tree, and an allowlisted authTokenInterceptor attaches bearer tokens only to URLs that match a configured pattern. The Keycloak adapter is the first of what's meant to be several — the core depends only on an AuthProvider port, so swapping identity providers is a one-file change rather than a rewrite. Published on npm as @ismailza/ngx-auth-client with a Docusaurus documentation site and CI that verifies every supported Angular major against the packed tarball.
Features
- ✓Auth state as signals — authenticated, claims, and roles update on login, logout, and token refresh with no manual event wiring
- ✓Functional authGuard — role requirements set via allOf / anyOf on route data, accumulating down the route tree
- ✓Allowlisted authTokenInterceptor — attaches bearer tokens only to requests matching a configured URL pattern; fails closed on misconfiguration
- ✓Keycloak adapter built on a provider-agnostic AuthProvider port, with a fake adapter (withFakeAuth) for testing without a real server
- ✓Tokens held in memory only — nothing written to localStorage or sessionStorage, where an XSS payload could read them
- ✓PKCE (S256) on by default and not silently disableable
- ✓SSR-safe — browser globals are guarded, the library no-ops on the server instead of throwing during prerender
- ✓Per-adapter role mapping (realm, resource, or a custom mapRoles function) so the core only ever sees a plain string[]
Challenges
- •Deriving reactive signal state from a library (keycloak-js) that only exposes getters and a single generic event
- •Designing a token-attachment interceptor safe by default — an allowlist that fails closed rather than a denylist that leaks
- •Keeping the core free of any identity-provider dependency while still shipping a full Keycloak adapter out of the box
- •Making role checks meaningful across providers that each store roles in a different claim shape
- •Verifying SSR safety without a running server in CI, across every supported Angular major
Solution
Built AuthService as a thin signal layer over an AuthProvider port, with the Keycloak adapter as the first (and so far only) implementation. Provider-specific behaviour lives behind optional capability interfaces the core feature-detects, so an adapter never has to pretend to support something it doesn't. Role mapping is entirely the adapter's responsibility — Keycloak's realm_access and resource_access are normalized into a flat string[] before the core ever sees them. The bearer interceptor defaults to same-origin /api/* only and treats an unmatched or misconfigured pattern as 'don't attach a token', not as an error to swallow. Browser-global access is guarded throughout so the library no-ops during server-side prerender instead of throwing.
Architecture
A provider function (provideAuth) supplies configuration through injection tokens, composed with an adapter factory such as withKeycloak(). AuthService exposes authenticated, claims, and roles as signals backed by the active AuthProvider. authGuard reads accumulated role requirements from route data and redirects unauthenticated users to the provider's login page or authenticated-but-unauthorized users to a configurable forbidden route. authTokenInterceptor reads a URL-pattern allowlist to decide whether to attach a bearer token, calling getToken() to refresh when the token is near expiry. A separate testing entry point ships withFakeAuth(), a real implementation of the same AuthProvider port rather than a mock. Built with ng-packagr into three entry points (core, /keycloak, /testing) as an Angular Package Format distributable.
Results & Impact
- ✓Published to npm as @ismailza/ngx-auth-client under MIT, currently at v0.1.1 with releases automated by release-please
- ✓Every supported Angular major (17–22) verified in CI against the packed npm tarball across all three entry points
- ✓Full documentation site at ismailza.github.io/ngx-auth-client, deployed from CI on every push to main
- ✓Zero identity-provider dependencies in the core package — keycloak-js is an optional peer, pulled in only by the Keycloak adapter
- ✓Tokens never touch Web Storage; session continuity comes from the provider's own SSO cookie via silent re-authentication
Frontend
Backend
Tools
Free to use, modify, and distribute with attribution.
More Projects
