@cl4im/angular
@cl4im/angular
Angular authentication library implementing the OAuth 2.0 Authorization Code flow with PKCE. Handles token acquisition, silent renewal, route guarding, and view state management for multi-realm applications.
Entry Points
| Import path | Purpose |
|---|---|
@cl4im/angular |
Configuration token and interface |
@cl4im/angular/core |
Services, guard, and provider function |
@cl4im/angular/util |
Pure JWT and PKCE utilities |
Installation
The library is published to npm as a scoped package:
npm install @cl4im/angular
Setup
Register the library in your app.config.ts using provideAuth:
import { provideAuth } from '@cl4im/angular/core';
import { AUTH_CONFIG } from '@cl4im/angular';
import { environment } from 'src/environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideAuth(environment.auth),
],
};
Or register the token directly if you need more control:
import { AUTH_CONFIG } from '@cl4im/angular';
providers: [
{ provide: AUTH_CONFIG, useValue: environment.auth },
]
AuthConfig
interface AuthConfig {
authority: string; // Base URL of the identity provider (e.g. http://localhost:4000)
realmId: string; // Realm name or UUID (e.g. "master")
clientId: string; // OAuth client_id registered in the identity provider
redirectUrl: string; // Callback URL registered as redirect_uri
responseType: string; // Always "code" for Authorization Code flow
scope: string; // Space-separated scopes (e.g. "openid profile email")
}
@cl4im/angular/core
AuthorizationService
Manages the full OAuth 2.0 + PKCE lifecycle.
import { AuthorizationService } from '@cl4im/angular/core';
@Component({ ... })
export class AppComponent {
constructor(private auth: AuthorizationService) {}
async ngOnInit() {
await this.auth.initialize(); // Restore session or trigger authorization
}
}
| Method / Property | Description |
|---|---|
initialize() |
Restores an existing session from storage. If no session exists, does nothing (call authorize() to start the flow). |
authorize() |
Generates a PKCE pair, stores the verifier, and redirects the browser to the identity provider's authorization endpoint. |
token(params) |
Exchanges an authorization code (or refresh token) for an access token. Called automatically by CallbackComponent. |
silentRenew() |
Attempts token renewal via a hidden iframe without user interaction. |
reauthorize() |
Clears current session and restarts the authorization flow. |
logout() |
Clears session storage and redirects to the identity provider's end-session endpoint. |
getToken() |
Returns the current access token string, or null if not authenticated. |
authenticated |
Boolean getter — true when a valid, non-expired token is held in memory. |
isAuth$ |
Observable<boolean> — emits on every authentication state change. |
Token renewal is scheduled automatically when a token is applied. Renewal fires at 80 % of the token's lifetime, before expiry.
ViewService
Manages the hierarchical route and breadcrumb state that drives @sp1ne/angular's navigation components. Every route change is reflected here.
import { ViewService } from '@cl4im/angular/core';
@Component({ ... })
export class MyComponent {
constructor(private view: ViewService) {}
ngOnInit() {
this.view.currentView$.subscribe(view => console.log(view));
}
}
| Method / Property | Description |
|---|---|
update(token) |
Fetches the view structure from the server for the current token and stores it. Called internally after authentication. |
view() |
Returns the raw View object for the current route. |
currentView$ |
Observable<View> — emits whenever the active view changes. |
breadCrumb$ |
Observable<BreadCrumb[]> — emits the breadcrumb trail for the current page. |
breadCrumb |
Synchronous getter for the current breadcrumb array. |
getLevel(url) |
Returns the hierarchy depth of a given URL segment. |
getUrlAtLevel(url, level) |
Extracts the URL segment at a specific hierarchy level (used by ViewGuard). |
getLevelControl(url) |
Returns the control structure for a given URL. |
updateBreadcrumb(routes) |
Manually sets the breadcrumb trail. |
RealmAppsService
Fetches the list of registered applications for a realm. Used by the header's app launcher.
import { RealmAppsService } from '@cl4im/angular/core';
const apps = await realmAppsService.getApplications(token);
// Returns: AppDef[] — [{ id, name, app_url }]
PrivateGuard
Route guard that blocks access to private routes when the user is not authenticated. Redirects to /login on failure.
import { PrivateGuard } from '@cl4im/angular/core';
const routes: Routes = [
{
path: 'dashboard',
canActivate: [PrivateGuard],
component: DashboardComponent,
},
];
@cl4im/angular/util
Pure utility functions with no Angular dependency — safe to use in services, guards, or plain TypeScript.
import { decodeJwt, isJwtExpired, generatePkcePair } from '@cl4im/angular/util';
const payload = decodeJwt<{ sub: string; exp: number }>(token);
const expired = isJwtExpired(token);
const { verifier, challenge } = await generatePkcePair();
| Function | Signature | Description |
|---|---|---|
decodeJwt |
<T>(token: string): T | null |
Decodes the JWT payload without verifying the signature. |
isJwtExpired |
(token: string): boolean |
Returns true if the token's exp claim is in the past. |
generatePkcePair |
(): Promise<{ verifier: string; challenge: string }> |
Generates a random code verifier and its SHA-256 S256 challenge. |
generateCodeVerifier |
(): string |
Generates a 128-character random Base64Url string. |
generateCodeChallenge |
(verifier: string): Promise<string> |
Computes the S256 challenge for a given verifier using SubtleCrypto. |
base64UrlEncode |
(bytes: Uint8Array): string |
Encodes a byte array as a Base64Url string (no padding). |
Token lifecycle
App starts
└─ initialize()
├─ valid token in storage → restore → schedule silent renewal
└─ no token → idle (caller must invoke authorize())
authorize()
└─ redirect to /authorize with PKCE challenge
Identity provider redirects to redirectUrl?code=...
└─ CallbackComponent (from @sp1ne/angular/shell)
└─ token(params) → store access token → schedule renewal
Silent renewal runs inside a hidden iframe at 80 % of the token lifetime and replaces the token in memory without any page navigation.
Peer dependencies
| Package | Version |
|---|---|
@angular/common |
^19.0.0 |
@angular/core |
^19.0.0 |
@angular/router |
^19.0.0 |
rxjs |
^7.0.0 |