Skip to content

Angular integration ​

The Angular example keeps one OIDC manager in a root service. The service completes browser callbacks, restores the current user, and exposes signals for templates.

Install ​

sh
npm install capacitor-oidc @capacitor/app
npx cap sync

Configure the provider ​

Keep deploy-specific values in an Angular environment file:

ts
// src/environments/environment.ts
export const environment = {
  authority: 'https://identity.example.com',
  clientId: 'public-app',
};

Create a root service ​

providedIn: 'root' gives the application one manager, independent of route and component lifetimes:

ts
@Injectable({ providedIn: 'root' })
export class OidcService {
  readonly user = signal<User | null>(null);

  private readonly manager = CapacitorUserManager.create({
    common: {
      authority: environment.authority,
      client_id: environment.clientId,
      scope: 'openid profile offline_access',
      automaticSilentRenew: false,
    },
    web: {
      settings: {
        redirect_uri: `${window.location.origin}/callback`,
        post_logout_redirect_uri: `${window.location.origin}/logout-callback`,
      },
    },
    native: {
      settings: {
        redirect_uri: 'capacitor-oidc-example:/callback',
        post_logout_redirect_uri: 'capacitor-oidc-example:/logout-callback',
      },
      options: { storageNamespace: 'angular-example' },
    },
  });
}

The runnable example keeps automatic renewal off so the bundled realm's 30-second test tokens can be renewed with the example's button. For a normal provider, enable automatic renewal and keep its expiry-notification threshold below the provider's access-token lifetime.

Initialize from the root component ​

The service handles browser callbacks before exposing the restored user:

ts
async initialize() {
  const auth = await this.manager;

  auth.events.addUserLoaded((user) => this.user.set(user));
  auth.events.addUserUnloaded(() => this.user.set(null));

  if (window.location.pathname === '/callback') {
    await auth.signinCallback();
    window.history.replaceState({}, '', '/');
  } else if (window.location.pathname === '/logout-callback') {
    await auth.signoutCallback();
    window.history.replaceState({}, '', '/');
  }

  this.user.set(await auth.getUser());
}

Call it once from the root component:

ts
export class AppComponent implements OnInit {
  readonly oidc = inject(OidcService);

  ngOnInit() {
    void this.oidc.initialize();
  }
}

Native callbacks finish inside the plugin and do not need Angular Router routes.

Bind actions ​

The root service can expose signin(), getValidUser(60), and signout() as methods. Components read the current user signal and do not hold their own manager.

Call dispose() only when the Angular application is shutting down.

Run the example ​

sh
npm ci
npm run build
npm run e2e:keycloak:up
npm --prefix examples/angular install
npm --prefix examples/angular run dev

Sign in with the disposable demo / demo account. Stop the local realm with npm run e2e:keycloak:down when finished.

This local realm workflow is for the browser example. Android resolves localhost inside the device or emulator, and native platforms should not use the example's cleartext HTTP authority. Before building for iOS or Android, replace environment.authority with an HTTPS authority reachable from that device and register the configured native callback scheme at the provider. See iOS and Android setup.