Skip to main content

Angular 17–22 · MIT licensed · signals-first, zoneless-ready

ngx-auth-client

Authentication state as signals, routes protected by a functional guard, and feature code with no identity-provider imports. Ships with a Keycloak adapter, built on a provider-agnostic port.

npm install @ismailza/ngx-auth-client keycloak-js

The layer every Angular app writes by hand

Deriving reactive auth state, guarding routes by role, signing requests and keeping tokens out of storage — written once, and kept behind a port you can swap.

State as signals

authenticated(), claims(), roles() and profile() are signals, so templates update on login, logout and refresh — including in a zoneless application, where getter-based state never re-renders.

Routes guarded by role

A functional authGuard with anyOf and allOf requirements that accumulate down the route tree — so a protected section is configured once, at its root.

Tokens never persisted

Nothing is written to localStorage or sessionStorage, where an XSS payload could read it. Continuity comes from the provider's SSO cookie, and PKCE S256 is on by default.

An allowlist for bearer tokens

The interceptor signs only the requests you name, refreshing the token first when it is near expiry. A pattern matching nothing attaches nothing — it fails closed rather than leaking a token to a third-party host.

Provider-agnostic by design

Three signals and four methods is the whole port. Roles are normalised by the adapter, optional features are feature-detected rather than faked, and swapping identity provider stays a one-file change.

Tests without a server

withFakeAuth() swaps in an in-memory adapter — a real implementation of the same port, not a stub. No Keycloak server, no mocked window.location, same code paths.

One provider call, then read state like any other signal

No event subscriptions to wire up, no derived signals to maintain, and nothing in your components that names your identity provider.

1. Configure it in app.config.ts

provideAuth(
withKeycloak({
url: 'https://auth.example.com',
realm: 'my-realm',
clientId: 'my-app',
}),
);

2. Read the state in a component

@Component({
template: `@if (auth.authenticated()) {
Hello {{ auth.claims()?.name }}
}`,
})
export class Header {
protected readonly auth = inject(AuthService);
}

That template updates on login, logout and token refresh — in a zoneless application too.
Meanwhile authGuard protects your routes by role, and authTokenInterceptor signs your API calls with a token it refreshes before it expires.

Ready to drop it in?

Install the package, add provideAuth() and register one interceptor. Tokens stay in memory, PKCE is on by default, and your tests run without a Keycloak server.

Read the installation guide