Skip to content

@xid-kit/angular

Angular 17+ standalone provider, RxJS service, functional route guards, and standalone components on top of @xid-kit/core.

Status

Package status is Current package. Angular 17+ standalone provider, RxJS service, functional guards, and standalone components are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.

Provider setup

Call provideXid in app.config.ts. It registers the XID_CLIENT injection token and wires an APP_INITIALIZER that calls client.load() on bootstrap. No NgModule required.

// app.config.ts
import { ApplicationConfig } from '@angular/core'
import { provideXid } from '@xid-kit/angular'

export const appConfig: ApplicationConfig = {
  providers: [
    provideXid({ apiUrl: 'https://app.xid.dev' }),
  ],
}

XidAuthService

import { Component, inject } from '@angular/core'
import { AsyncPipe } from '@angular/common'
import { XidAuthService } from '@xid-kit/angular'

@Component({
  selector: 'app-header',
  standalone: true,
  imports: [AsyncPipe],
  template: `
    @if (auth.isLoaded$ | async) {
      @if (auth.isSignedIn$ | async) {
        <span>{{ (auth.user$ | async)?.primaryEmailAddress }}</span>
      } @else {
        <a routerLink="/sign-in">Sign in</a>
      }
    }
  `,
})
export class HeaderComponent {
  readonly auth = inject(XidAuthService)
}

Angular signals bridge

Use toSignal() from @angular/core/rxjs-interop to convert observables to signals for template reads.

import { toSignal } from '@angular/core/rxjs-interop'
import { inject } from '@angular/core'
import { XidAuthService } from '@xid-kit/angular'

@Component({ standalone: true, ... })
export class MyComponent {
  readonly #auth = inject(XidAuthService)
  readonly user = toSignal(this.#auth.user$, { initialValue: null })
}

Route guards

import { Routes } from '@angular/router'
import { authGuard, hasOrganizationGuard, hasPermissionGuard } from '@xid-kit/angular'

export const routes: Routes = [
  {
    path: 'dashboard',
    canActivate: [authGuard()],
    loadComponent: () => import('./dashboard.component').then(m => m.DashboardComponent),
  },
  {
    path: 'admin',
    canActivate: [hasPermissionGuard('org:settings:write')],
    loadComponent: () => import('./admin.component').then(m => m.AdminComponent),
  },
]

Standalone components

<!-- template -->
<xid-sign-in-button signInUrl="/sign-in" redirectUrl="/dashboard">Log in</xid-sign-in-button>
<xid-sign-out-button redirectUrl="/home">Log out</xid-sign-out-button>

Exported API

Export Kind Purpose
provideXid function Registers XID_CLIENT singleton and APP_INITIALIZER; accepts ProvideXidOptions
XID_CLIENT InjectionToken The raw XidClient instance; prefer XidAuthService for most use cases
XidAuthService service RxJS observables: state$, isLoaded$, isSignedIn$, user$, session$, organization$; plus getToken, signOut, setActiveOrganization, setActiveSession
authGuard CanActivateFn factory Redirects to /sign-in when user is not signed in
hasOrganizationGuard CanActivateFn factory Redirects when no active organization context is present
hasPermissionGuard CanActivateFn factory Redirects when user lacks the specified permission
SignInButton standalone component Selector xid-sign-in-button; inputs signInUrl, redirectUrl, ariaLabel
SignOutButton standalone component Selector xid-sign-out-button; inputs sessionId, redirectUrl, ariaLabel; shows aria-busy while signing out
Navigation

Type to search...

Use arrow keys to navigateEnter to selectEscape to close