@strivacity/sdk-angular 3.0.0-rc.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,22 @@
1
1
  # @strivacity/sdk-angular
2
2
 
3
- > **The SDK supports Angular version 16 and above**
3
+ An Angular library that integrates Strivacity's policy-driven authentication journeys into your application using the OAuth 2.0 PKCE flow. Supports `redirect`, `popup`, `native`, and `embedded` modes.
4
4
 
5
- ## Example Apps
5
+ See our [Developer Portal](https://www.strivacity.com/learn-support/developer-hub) to get started with developing with the Strivacity product.
6
+
7
+ ## Overview
8
+
9
+ This SDK allows you to integrate Strivacity's policy-driven journeys into your Angular application. It wraps the `@strivacity/sdk-core` library as an Angular service and provides `StrivacityAuthModule` for NgModule apps and `provideStrivacity()` for standalone apps. The SDK uses the OAuth 2.0 PKCE flow to authenticate with Strivacity. For detailed configuration options, available modes, and advanced usage refer to the [`@strivacity/sdk-core` documentation](https://github.com/Strivacity/sdk-js/blob/main/packages/sdk-core/README.md).
10
+
11
+ ## Demo Application
6
12
 
7
13
  - [Example app](https://github.com/Strivacity/sdk-js/tree/main/apps/angular)
8
14
  - [Ionic Example app](https://github.com/Strivacity/sdk-js/tree/main/apps/ionic-angular)
9
15
 
16
+ ## Requirements
17
+
18
+ - Angular: 17+
19
+
10
20
  ## Install
11
21
 
12
22
  ```bash
@@ -15,15 +25,15 @@ npm install @strivacity/sdk-angular
15
25
 
16
26
  ## Usage
17
27
 
18
- ### Add this to your application configuration
28
+ ### Initialization
19
29
 
20
- #### NgModule - Import `StrivacityAuthModule` to your application:
30
+ #### NgModule apps
21
31
 
22
- `app.module.ts`
32
+ Import `StrivacityAuthModule` in your `AppModule`:
23
33
 
24
34
  ```ts
35
+ // app.module.ts
25
36
  import { NgModule } from '@angular/core';
26
-
27
37
  import { AppComponent } from './app.component';
28
38
  import { StrivacityAuthModule } from '@strivacity/sdk-angular';
29
39
 
@@ -31,7 +41,7 @@ import { StrivacityAuthModule } from '@strivacity/sdk-angular';
31
41
  declarations: [AppComponent],
32
42
  imports: [
33
43
  ...StrivacityAuthModule.forRoot({
34
- mode: 'redirect', // or 'popup' or 'native'
44
+ mode: 'redirect', // or 'popup', 'native', 'embedded'
35
45
  issuer: 'https://<YOUR_DOMAIN>',
36
46
  scopes: ['openid', 'profile'],
37
47
  clientId: '<YOUR_CLIENT_ID>',
@@ -43,18 +53,19 @@ import { StrivacityAuthModule } from '@strivacity/sdk-angular';
43
53
  export class AppModule {}
44
54
  ```
45
55
 
46
- #### Standalone mode - Configure SDK for your application:
56
+ #### Standalone apps
47
57
 
48
- `app.config.ts`
58
+ Use `provideStrivacity()` in your application config:
49
59
 
50
60
  ```ts
61
+ // app.config.ts
51
62
  import { ApplicationConfig } from '@angular/core';
52
63
  import { provideStrivacity } from '@strivacity/sdk-angular';
53
64
 
54
65
  export const appConfig: ApplicationConfig = {
55
66
  providers: [
56
67
  ...provideStrivacity({
57
- mode: 'redirect', // or 'popup' or 'native'
68
+ mode: 'redirect', // or 'popup', 'native', 'embedded'
58
69
  issuer: 'https://<YOUR_DOMAIN>',
59
70
  scopes: ['openid', 'profile'],
60
71
  clientId: '<YOUR_CLIENT_ID>',
@@ -64,17 +75,23 @@ export const appConfig: ApplicationConfig = {
64
75
  };
65
76
  ```
66
77
 
67
- ### How to use the SDK in your components
78
+ Inject `StrivacityAuthService` into any component to access authentication state:
68
79
 
69
- #### Redirect mode
80
+ ```ts
81
+ import { Component } from '@angular/core';
82
+ import { StrivacityAuthService } from '@strivacity/sdk-angular';
70
83
 
71
- When using redirect mode, the authentication flow involves two main components: a login page that initiates the authentication process, and a callback page that handles the response from the identity provider.
84
+ @Component({ standalone: true, selector: 'app-root', template: '' })
85
+ export class AppComponent {
86
+ constructor(private strivacityAuthService: StrivacityAuthService) {}
87
+ }
88
+ ```
72
89
 
73
- In **redirect mode**, users are redirected to the identity provider's login page in the same browser window. After successful authentication, they are redirected back to your application's callback URL.
90
+ ### Redirect / Popup mode
74
91
 
75
- ##### Login page example
92
+ In `redirect` mode the user is taken to the identity provider in the same window; in `popup` mode authentication happens in a popup. Both are initiated the same way from code.
76
93
 
77
- The login page is where users start the authentication process. This component automatically triggers the login flow when the page loads, redirecting users to the identity provider for authentication.
94
+ #### Login page example
78
95
 
79
96
  ```html
80
97
  <!-- login.component.html -->
@@ -102,9 +119,9 @@ export class LoginComponent implements OnInit {
102
119
  }
103
120
  ```
104
121
 
105
- ##### Callback page example
122
+ #### Callback page example
106
123
 
107
- The callback page handles the response from the identity provider after successful authentication. It processes the authentication result, extracts the tokens, and redirects users to their intended destination (typically a protected page like a profile or dashboard).
124
+ The callback page handles the response from the identity provider. It calls `handleCallback()` and redirects to `/profile` on success:
108
125
 
109
126
  ```html
110
127
  <!-- callback.component.html -->
@@ -165,11 +182,7 @@ export class CallbackComponent implements OnInit, OnDestroy {
165
182
  }
166
183
  ```
167
184
 
168
- ##### Profile page example
169
-
170
- The profile page displays user information and authentication details after successful login. It uses the `StrivacityAuthService` to access the authentication state and display relevant data such as access tokens, ID token claims, and expiration status.
171
-
172
- We check if the user is authenticated and display their profile information. If the user is not authenticated, we redirect them to the login page.
185
+ #### Profile page example
173
186
 
174
187
  ```html
175
188
  <!-- profile.component.html -->
@@ -178,36 +191,16 @@ We check if the user is authenticated and display their profile information. If
178
191
  <h1>Loading...</h1>
179
192
  } @else {
180
193
  <dl>
181
- <dt>
182
- <strong>accessToken</strong>
183
- </dt>
184
- <dd>
185
- <pre>{{ session.accessToken | json }}</pre>
186
- </dd>
187
- <dt>
188
- <strong>refreshToken</strong>
189
- </dt>
190
- <dd>
191
- <pre>{{ session.refreshToken | json }}</pre>
192
- </dd>
193
- <dt>
194
- <strong>accessTokenExpired</strong>
195
- </dt>
196
- <dd>
197
- <pre>{{ session.accessTokenExpired | json }}</pre>
198
- </dd>
199
- <dt>
200
- <strong>accessTokenExpirationDate</strong>
201
- </dt>
202
- <dd>
203
- <pre>{{ session.accessTokenExpirationDate | date: 'medium' }}</pre>
204
- </dd>
205
- <dt>
206
- <strong>claims</strong>
207
- </dt>
208
- <dd>
209
- <pre>{{ session.idTokenClaims | json }}</pre>
210
- </dd>
194
+ <dt><strong>accessToken</strong></dt>
195
+ <dd><pre>{{ session.accessToken | json }}</pre></dd>
196
+ <dt><strong>refreshToken</strong></dt>
197
+ <dd><pre>{{ session.refreshToken | json }}</pre></dd>
198
+ <dt><strong>accessTokenExpired</strong></dt>
199
+ <dd><pre>{{ session.accessTokenExpired | json }}</pre></dd>
200
+ <dt><strong>accessTokenExpirationDate</strong></dt>
201
+ <dd><pre>{{ session.accessTokenExpirationDate | date: 'medium' }}</pre></dd>
202
+ <dt><strong>claims</strong></dt>
203
+ <dd><pre>{{ session.idTokenClaims | json }}</pre></dd>
211
204
  </dl>
212
205
  }
213
206
  </section>
@@ -252,11 +245,9 @@ export class ProfileComponent implements OnDestroy {
252
245
  }
253
246
  ```
254
247
 
255
- ##### Logout page example
256
-
257
- The logout page handles user logout by terminating their session. The `postLogoutRedirectUri` parameter is optional and specifies where users should be redirected after logout. If not provided, users will be redirected to the identity provider's logout page.
248
+ #### Logout page example
258
249
 
259
- This URI must be configured in the Admin Console as an allowed post-logout redirect URI for your application.
250
+ The `postLogoutRedirectUri` parameter is optional and specifies where users are redirected after logout. This URI must be configured in the Admin Console as an allowed post-logout redirect URI.
260
251
 
261
252
  ```html
262
253
  <!-- logout.component.html -->
@@ -299,9 +290,7 @@ export class LogoutComponent implements OnInit, OnDestroy {
299
290
  }
300
291
  ```
301
292
 
302
- ##### Component example
303
-
304
- Here's a simple component example that demonstrates how to use the SDK in a component with login/logout functionality:
293
+ #### Component example
305
294
 
306
295
  ```html
307
296
  <!-- app.component.html -->
@@ -317,7 +306,6 @@ Here's a simple component example that demonstrates how to use the SDK in a comp
317
306
  ```ts
318
307
  // app.component.ts
319
308
  import { Component, OnDestroy } from '@angular/core';
320
- import { Router } from '@angular/router';
321
309
  import { Subscription } from 'rxjs';
322
310
  import { StrivacityAuthService } from '@strivacity/sdk-angular';
323
311
 
@@ -331,10 +319,7 @@ export class AppComponent implements OnDestroy {
331
319
  isAuthenticated = false;
332
320
  name = '';
333
321
 
334
- constructor(
335
- private router: Router,
336
- private strivacityAuthService: StrivacityAuthService,
337
- ) {
322
+ constructor(private strivacityAuthService: StrivacityAuthService) {
338
323
  this.subscription.add(
339
324
  this.strivacityAuthService.session$.subscribe((session) => {
340
325
  this.isAuthenticated = session.isAuthenticated;
@@ -348,30 +333,25 @@ export class AppComponent implements OnDestroy {
348
333
  }
349
334
 
350
335
  login(): void {
351
- this.strivacityAuthService.login().subscribe({
352
- next: () => {
353
- this.router.navigateByUrl('/profile');
354
- },
355
- });
336
+ this.strivacityAuthService.login().subscribe();
356
337
  }
357
338
 
358
339
  logout(): void {
359
- this.strivacityAuthService.logout().subscribe({
360
- next: () => {
361
- this.router.navigateByUrl('/');
362
- },
363
- });
340
+ this.strivacityAuthService.logout().subscribe();
364
341
  }
365
342
  }
366
343
  ```
367
344
 
368
- #### Native mode
345
+ ### Native mode
369
346
 
370
- If you are using `native` mode, you can use the `sty-login-renderer` component to render the login UI.
347
+ In `native` mode the `<sty-login-renderer>` component renders the authentication UI inline using your custom widget components. You can define custom Angular components for each input type; see [Example widgets](https://github.com/Strivacity/sdk-js/tree/main/apps/angular/src/app/components/widgets).
371
348
 
372
- To customize the UI components used in the authentication flows, define the `widgets` object in your component.
349
+ The example widgets use SCSS for styling and Luxon for date handling:
373
350
 
374
- ##### Example widgets
351
+ ```bash
352
+ npm install sass luxon
353
+ npm install --save-dev @types/luxon
354
+ ```
375
355
 
376
356
  ```ts
377
357
  import {
@@ -405,55 +385,42 @@ export const widgets = {
405
385
  };
406
386
  ```
407
387
 
408
- You can find example widgets here: [Example widgets](https://github.com/Strivacity/sdk-js/tree/main/apps/angular/src/app/components/widgets)
388
+ #### Login page example
409
389
 
410
- ##### Login page example
411
-
412
- The native mode login page provides a fully customizable authentication experience rendered directly within your application. Unlike redirect mode, native mode keeps users on your site throughout the entire authentication process using the `sty-login-renderer` component.
413
-
414
- This example demonstrates how to handle session management, implement callback functions for various authentication events, and manage URL parameters for session continuity.
390
+ The login page extracts `session_id` from the URL on load, cleans up the URL, and passes it to the renderer. When a `session_id` is present the renderer calls `startSession(sessionId)` to resume the existing flow instead of starting a new one.
415
391
 
416
392
  ```html
417
393
  <!-- login.component.html -->
418
- <section>
419
- <sty-login-renderer
420
- [widgets]="widgets"
421
- [sessionId]="sessionId"
422
- (fallback)="onFallback($event)"
423
- (login)="onLogin()"
424
- (error)="onError($event)"
425
- (globalMessage)="onGlobalMessage($event)"
426
- (blockReady)="onBlockReady($event)"
427
- ></sty-login-renderer>
428
- </section>
394
+ <sty-login-renderer
395
+ [widgets]="widgets"
396
+ [sessionId]="sessionId"
397
+ (login)="onLogin()"
398
+ (fallback)="onFallback($event)"
399
+ (error)="onError($event)"
400
+ (globalMessage)="onGlobalMessage($event)"
401
+ (blockReady)="onBlockReady($event)"
402
+ />
429
403
  ```
430
404
 
431
405
  ```ts
432
406
  // login.component.ts
433
407
  import { Component, OnInit } from '@angular/core';
434
408
  import { Router } from '@angular/router';
435
- import { StrivacityAuthService, FallbackError, StyLoginRenderer, LoginFlowState } from '@strivacity/sdk-angular';
436
- import { widgets } from '@/components/widgets'; // Import your custom widgets
409
+ import { StyLoginRenderer, FallbackError, type LoginFlowState } from '@strivacity/sdk-angular';
410
+ import { widgets } from './components/widgets';
437
411
 
438
412
  @Component({
439
413
  standalone: true,
440
- imports: [StyLoginRenderer],
441
414
  selector: 'app-login',
442
415
  templateUrl: './login.component.html',
416
+ imports: [StyLoginRenderer],
443
417
  })
444
418
  export class LoginComponent implements OnInit {
445
- readonly widgets = widgets;
419
+ widgets = widgets;
446
420
  sessionId: string | null = null;
447
421
 
448
- constructor(
449
- private router: Router,
450
- private strivacityAuthService: StrivacityAuthService,
451
- ) {}
422
+ constructor(private router: Router) {}
452
423
 
453
- /**
454
- * Extract session_id from URL parameters and clean up the URL
455
- * This is necessary for maintaining session state across external login providers
456
- */
457
424
  ngOnInit(): void {
458
425
  if (window.location.search !== '') {
459
426
  const url = new URL(window.location.href);
@@ -463,51 +430,26 @@ export class LoginComponent implements OnInit {
463
430
  }
464
431
  }
465
432
 
466
- /**
467
- * Called when authentication is successful
468
- * Redirects user to the profile page
469
- */
470
- async onLogin(): Promise<void> {
471
- await this.router.navigateByUrl('/profile');
433
+ onLogin(): void {
434
+ this.router.navigateByUrl('/profile');
472
435
  }
473
436
 
474
- /**
475
- * Called when native flow cannot handle the authentication
476
- * Falls back to redirect mode by navigating to the provided URL
477
- * @param error - FallbackError containing the fallback URL and message
478
- */
479
437
  onFallback(error: FallbackError): void {
480
438
  if (error.url) {
481
- console.log(`Fallback: ${error.url}`);
482
- location.href = error.url.toString();
439
+ window.location.href = error.url.toString();
483
440
  } else {
484
- console.error(`FallbackError without URL: ${error.message}`);
485
441
  alert(error);
486
442
  }
487
443
  }
488
444
 
489
- /**
490
- * Called when an error occurs during the authentication process
491
- * @param error - Error message describing what went wrong
492
- */
493
445
  onError(error: string): void {
494
- console.error(`Error: ${error}`);
495
446
  alert(error);
496
447
  }
497
448
 
498
- /**
499
- * Called when the authentication flow wants to display a global message
500
- * @param message - Message to display to the user
501
- */
502
449
  onGlobalMessage(message: string): void {
503
450
  alert(message);
504
451
  }
505
452
 
506
- /**
507
- * Called when the authentication flow transitions between states
508
- * Useful for tracking flow progress and inject custom logic such as logging or analytics
509
- * @param params - Object containing previous and current flow states
510
- */
511
453
  onBlockReady({ previousState, state }: { previousState: LoginFlowState; state: LoginFlowState }): void {
512
454
  console.log('previousState', previousState);
513
455
  console.log('state', state);
@@ -515,11 +457,9 @@ export class LoginComponent implements OnInit {
515
457
  }
516
458
  ```
517
459
 
518
- ##### Callback page example
519
-
520
- The native mode callback page handles authentication responses when external identity providers redirect back to your application. This page checks for session IDs in the URL parameters and either continues the native flow or falls back to standard callback handling.
460
+ #### Callback page example
521
461
 
522
- This component is essential for handling social login providers (like Google, Facebook, etc.) that require redirect-based authentication even within native mode flows.
462
+ When a `session_id` is present in the URL the native flow is resumed by forwarding it to the login page. Otherwise the standard `handleCallback()` path is used:
523
463
 
524
464
  ```html
525
465
  <!-- callback.component.html -->
@@ -549,7 +489,7 @@ import { StrivacityAuthService } from '@strivacity/sdk-angular';
549
489
  templateUrl: './callback.component.html',
550
490
  })
551
491
  export class CallbackComponent implements OnInit, OnDestroy {
552
- readonly subscription = new Subscription();
492
+ private subscription = new Subscription();
553
493
  error: string | null = null;
554
494
  errorDescription: string | null = null;
555
495
 
@@ -560,26 +500,70 @@ export class CallbackComponent implements OnInit, OnDestroy {
560
500
  ) {}
561
501
 
562
502
  ngOnInit(): void {
563
- const url = new URL(window.location.href);
503
+ const url = new URL(location.href);
564
504
  const sessionId = url.searchParams.get('session_id');
565
505
 
566
506
  if (sessionId) {
567
507
  this.router.navigate(['/login'], { queryParams: { session_id: sessionId } });
568
- return;
508
+ } else {
509
+ this.subscription.add(
510
+ this.strivacityAuthService.handleCallback().subscribe({
511
+ next: () => {
512
+ this.router.navigateByUrl('/profile');
513
+ },
514
+ error: (err) => {
515
+ this.error = this.route.snapshot.queryParamMap.get('error');
516
+ this.errorDescription = this.route.snapshot.queryParamMap.get('error_description');
517
+ console.error('Error during callback handling:', err);
518
+ },
519
+ }),
520
+ );
569
521
  }
522
+ }
570
523
 
571
- this.subscription.add(
572
- this.strivacityAuthService.handleCallback().subscribe({
573
- next: () => {
574
- this.router.navigateByUrl('/profile');
575
- },
576
- error: (err) => {
577
- this.error = this.route.snapshot.queryParamMap.get('error');
578
- this.errorDescription = this.route.snapshot.queryParamMap.get('error_description');
579
- console.error('Error during callback handling:', err);
580
- },
581
- }),
582
- );
524
+ ngOnDestroy(): void {
525
+ this.subscription.unsubscribe();
526
+ }
527
+ }
528
+ ```
529
+
530
+ #### Entry page example
531
+
532
+ The entry page processes flows started by an external process (e.g. password reset) by calling `entry()` to extract the necessary parameters to resume the flow and forwarding them to the callback page:
533
+
534
+ ```ts
535
+ // entry.component.ts
536
+ import { Component, OnInit, OnDestroy } from '@angular/core';
537
+ import { Router } from '@angular/router';
538
+ import { Subscription, firstValueFrom } from 'rxjs';
539
+ import { StrivacityAuthService } from '@strivacity/sdk-angular';
540
+
541
+ @Component({
542
+ standalone: true,
543
+ selector: 'app-entry',
544
+ template: '<section><h1>Loading...</h1></section>',
545
+ })
546
+ export class EntryComponent implements OnInit, OnDestroy {
547
+ readonly subscription = new Subscription();
548
+
549
+ constructor(
550
+ private router: Router,
551
+ private strivacityAuthService: StrivacityAuthService,
552
+ ) {}
553
+
554
+ async ngOnInit(): Promise<void> {
555
+ try {
556
+ const data = await firstValueFrom(this.strivacityAuthService.entry());
557
+
558
+ if (data && Object.keys(data).length > 0) {
559
+ await this.router.navigate(['/callback'], { queryParams: data });
560
+ } else {
561
+ await this.router.navigateByUrl('/');
562
+ }
563
+ } catch (error) {
564
+ console.error('Entry failed:', error);
565
+ await this.router.navigateByUrl('/');
566
+ }
583
567
  }
584
568
 
585
569
  ngOnDestroy(): void {
@@ -588,52 +572,81 @@ export class CallbackComponent implements OnInit, OnDestroy {
588
572
  }
589
573
  ```
590
574
 
591
- ##### Profile page example
575
+ #### Profile page example
592
576
 
593
- Same as the profile page example in redirect mode.
577
+ Same as the profile page example in redirect/popup mode.
594
578
 
595
- ##### Logout page example
579
+ #### Logout page example
596
580
 
597
- Same as the logout page example in redirect mode.
581
+ Same as the logout page example in redirect/popup mode.
598
582
 
599
- ## Logging
583
+ ### Embedded mode
600
584
 
601
- The SDK supports optional logging to help you debug authentication flows and monitor SDK behavior. You can enable the built-in console logger or provide your own custom logger implementation.
585
+ In `embedded` mode the `<sty-login>` web component (loaded via `bundle.js` from the cluster) handles rendering. Import the bundle in your `main.ts` to register the Strivacity web components, and add `CUSTOM_ELEMENTS_SCHEMA` to your module or component:
602
586
 
603
- ### Using the Default Logger
587
+ ```ts
588
+ // main.ts
589
+ import { bootstrapApplication } from '@angular/platform-browser';
590
+ import { appConfig } from './app/app.config';
591
+ import { AppComponent } from './app/app.component';
604
592
 
605
- Enable the default console logger by adding the `logging` option when configuring the SDK:
593
+ void import(`${environment.issuer}/assets/components/bundle.js`);
606
594
 
607
- #### NgModule Configuration
595
+ bootstrapApplication(AppComponent, appConfig);
596
+ ```
608
597
 
609
- ```typescript
610
- import { NgModule } from '@angular/core';
611
- import { StrivacityAuthModule } from '@strivacity/sdk-angular';
612
- import { DefaultLogging } from '@strivacity/sdk-core';
598
+ ```ts
599
+ // login.component.ts (embedded mode)
600
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
613
601
 
614
- @NgModule({
615
- declarations: [AppComponent],
616
- imports: [
617
- ...StrivacityAuthModule.forRoot({
618
- mode: 'redirect',
619
- issuer: 'https://<YOUR_DOMAIN>',
620
- scopes: ['openid', 'profile'],
621
- clientId: '<YOUR_CLIENT_ID>',
622
- redirectUri: '<YOUR_REDIRECT_URI>',
623
- logging: DefaultLogging, // Enable built-in console logging
624
- }),
625
- ],
626
- bootstrap: [AppComponent],
602
+ @Component({
603
+ standalone: true,
604
+ selector: 'app-login',
605
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
606
+ template: `
607
+ <sty-notifications></sty-notifications>
608
+ <sty-login [shortAppId]="shortAppId" [sessionId]="sessionId" (close)="onClose()" (login)="onLogin()" (error)="onError($event.detail)"></sty-login>
609
+ <sty-language-selector></sty-language-selector>
610
+ `,
627
611
  })
628
- export class AppModule {}
612
+ export class LoginComponent {
613
+ shortAppId: string | null = null;
614
+ sessionId: string | null = null;
615
+
616
+ constructor(private router: Router) {
617
+ if (location.search !== '') {
618
+ const url = new URL(window.location.href);
619
+ this.shortAppId = url.searchParams.get('short_app_id');
620
+ this.sessionId = url.searchParams.get('session_id');
621
+ url.search = '';
622
+ history.replaceState({}, '', url.toString());
623
+ }
624
+ }
625
+
626
+ onLogin(): void {
627
+ this.router.navigateByUrl('/profile');
628
+ }
629
+
630
+ onClose(): void {
631
+ location.reload();
632
+ }
633
+
634
+ onError(detail: string): void {
635
+ alert(detail);
636
+ }
637
+ }
629
638
  ```
630
639
 
631
- #### Standalone Configuration
640
+ ## Logging
632
641
 
633
- ```typescript
634
- import { ApplicationConfig } from '@angular/core';
635
- import { provideStrivacity } from '@strivacity/sdk-angular';
636
- import { DefaultLogging } from '@strivacity/sdk-core';
642
+ The SDK supports optional logging to help you debug authentication flows and monitor SDK behavior. You can enable the built-in console logger or provide your own custom logger implementation.
643
+
644
+ ### Using the Default Logger
645
+
646
+ Enable the default console logger by adding the `logging` option when configuring the SDK:
647
+
648
+ ```ts
649
+ import { provideStrivacity, DefaultLogging } from '@strivacity/sdk-angular';
637
650
 
638
651
  export const appConfig: ApplicationConfig = {
639
652
  providers: [
@@ -643,7 +656,7 @@ export const appConfig: ApplicationConfig = {
643
656
  scopes: ['openid', 'profile'],
644
657
  clientId: '<YOUR_CLIENT_ID>',
645
658
  redirectUri: '<YOUR_REDIRECT_URI>',
646
- logging: DefaultLogging, // Enable built-in console logging
659
+ logging: DefaultLogging,
647
660
  }),
648
661
  ],
649
662
  };
@@ -653,7 +666,7 @@ The default logger writes to the browser console and automatically prefixes mess
653
666
 
654
667
  ### Creating a Custom Logger
655
668
 
656
- You can provide your own logger by implementing the `SDKLogging` interface with four methods: `debug`, `info`, `warn`, and `error`. An optional `xEventId` property is honored for log correlation.
669
+ Implement the `SDKLogging` interface and pass your class to the `logging` option:
657
670
 
658
671
  ```typescript
659
672
  import type { SDKLogging } from '@strivacity/sdk-angular';
@@ -662,7 +675,6 @@ export class MyLogger implements SDKLogging {
662
675
  xEventId?: string;
663
676
 
664
677
  debug(message: string): void {
665
- // Send to your logging pipeline
666
678
  console.debug(this.xEventId ? `[${this.xEventId}] ${message}` : message);
667
679
  }
668
680
 
@@ -680,212 +692,76 @@ export class MyLogger implements SDKLogging {
680
692
  }
681
693
  ```
682
694
 
683
- Then register your custom logger when configuring the SDK:
684
-
685
- #### Standalone Configuration
686
-
687
- ```typescript
688
- import { provideStrivacity } from '@strivacity/sdk-angular';
689
- import { MyLogger } from './logging/MyLogger';
690
-
691
- export const appConfig: ApplicationConfig = {
692
- providers: [
693
- ...provideStrivacity({
694
- mode: 'redirect',
695
- issuer: 'https://<YOUR_DOMAIN>',
696
- scopes: ['openid', 'profile'],
697
- clientId: '<YOUR_CLIENT_ID>',
698
- redirectUri: '<YOUR_REDIRECT_URI>',
699
- logging: MyLogger, // Use your custom logger
700
- }),
701
- ],
702
- };
703
- ```
704
-
705
- ### Logger Interface
706
-
707
- The `SDKLogging` interface requires the following methods:
708
-
709
- - **`debug(message: string): void`** - Log debug-level messages
710
- - **`info(message: string): void`** - Log informational messages
711
- - **`warn(message: string): void`** - Log warning messages
712
- - **`error(message: string, error: Error): void`** - Log error messages with error objects
713
-
714
- The optional `xEventId` property, when set by the SDK, provides a correlation ID to trace related log messages across the authentication flow.
695
+ The `SDKLogging` interface requires `debug`, `info`, `warn`, and `error` methods. The optional `xEventId` property, when set by the SDK, provides a correlation ID to trace related log messages across the authentication flow.
715
696
 
716
697
  ## API Documentation
717
698
 
718
- #### `StrivacityAuthService`
699
+ ### `StrivacityAuthService`
719
700
 
720
- Service that manages Strivacity authentication flows. Supports `PopupFlow`, `RedirectFlow`, or `NativeFlow` types.
721
-
722
- **Constructor**
723
-
724
- ```typescript
725
- constructor(@Inject(STRIVACITY_SDK) public options: Options);
726
- ```
727
-
728
- - `options`: SDK configuration options.
701
+ An injectable Angular service providing reactive authentication state and methods.
729
702
 
730
703
  **Properties**
731
704
 
732
- - **`session$`**: An observable that emits the current authentication session state. It provides updates on the authentication status, token information, and other relevant session details.
705
+ - **`sdk: RedirectFlow | PopupFlow | NativeFlow`**: The underlying SDK flow instance.
706
+ - **`session$: Observable<Session>`**: Observable stream of the current session state.
733
707
 
734
- **Session Object Structure**:
708
+ **Session type**
735
709
 
736
- ```typescript
737
- interface Session = {
738
- /**
739
- * Indicates whether the session is in the process of loading or initializing.
740
- * When `true`, the session information might not be fully available yet.
741
- */
742
- loading: boolean;
743
-
744
- /**
745
- * Indicates whether the user is currently authenticated.
746
- * `true` if the user is authenticated, otherwise `false`.
747
- */
748
- isAuthenticated: boolean;
749
-
750
- /**
751
- * The claims contained in the ID token if the user is authenticated.
752
- * This includes information such as the user's identity and authentication context.
753
- * If the user is not authenticated, this will be `null`.
754
- */
755
- idTokenClaims: IdTokenClaims | null;
756
-
757
- /**
758
- * The current access token used for authorizing API requests.
759
- * This token is `null` if the user is not authenticated or if the token has not been set.
760
- */
761
- accessToken: string | null;
762
-
763
- /**
764
- * The current refresh token used to obtain a new access token when the current one expires.
765
- * This token is `null` if the user is not authenticated or if the token has not been set.
766
- */
767
- refreshToken: string | null;
768
-
769
- /**
770
- * Indicates whether the current access token has expired.
771
- * `true` if the token is expired, otherwise `false`.
772
- */
773
- accessTokenExpired: boolean;
774
-
775
- /**
776
- * The expiration date of the current access token in Unix time (milliseconds since epoch).
777
- * If the access token is not available or the session is not authenticated, this will be `null`.
778
- */
779
- accessTokenExpirationDate: number | null;
780
- };
781
- ```
710
+ - **`loading: boolean`**: `true` while the session is being initialized.
711
+ - **`isAuthenticated: boolean`**: `true` when the user has a valid session.
712
+ - **`idTokenClaims: IdTokenClaims | null`**: Claims from the ID token, or `null` if not authenticated.
713
+ - **`accessToken: string | null`**: The current access token.
714
+ - **`refreshToken: string | null`**: The current refresh token.
715
+ - **`accessTokenExpired: boolean`**: `true` when the access token has expired.
716
+ - **`accessTokenExpirationDate: number | null`**: Expiration timestamp (Unix seconds) of the access token.
782
717
 
783
718
  **Methods**
784
719
 
785
- - **`isAuthenticated()`**: Checks if the user is authenticated.
720
+ - **`isAuthenticated(): boolean`**: Returns whether the user is currently authenticated.
721
+ - **`login(options?: LoginOptions): Observable<void>`**: Initiates login.
722
+ - **`register(options?: RegisterOptions): Observable<void>`**: Initiates registration.
723
+ - **`refresh(): Observable<void>`**: Refreshes the user's session.
724
+ - **`revoke(): Observable<void>`**: Revokes the current session tokens.
725
+ - **`logout(options?: LogoutOptions): Observable<void>`**: Logs the user out.
726
+ - **`handleCallback(url?: string): Observable<void>`**: Processes the authorization callback.
727
+ - **`entry(): Observable<Record<string, string>>`**: Processes an externally-initiated flow URL and returns the parameters needed to resume the flow.
786
728
 
787
- ```typescript
788
- isAuthenticated(): Observable<boolean>;
789
- ```
729
+ ---
790
730
 
791
- - **`login(options?: LoginOptions)`**: Logs the user in using the specified options.
731
+ ### `StyLoginRenderer` component
792
732
 
793
- ```typescript
794
- login(options?: LoginOptions): Observable<void>;
795
- ```
733
+ Used in `native` mode to render the authentication UI with your own widget components.
796
734
 
797
- - **`register(options?: RegisterOptions)`**: Registers a new user using the specified options.
735
+ **Selector:** `sty-login-renderer`
798
736
 
799
- ```typescript
800
- register(options?: RegisterOptions): Observable<void>;
801
- ```
737
+ **Inputs**
802
738
 
803
- - **`refresh()`**: Refreshes the current authentication session.
739
+ - **`params?: NativeParams`**: Additional parameters for the native login flow.
740
+ - **`widgets?: PartialRecord<WidgetType, Type<any>>`**: Custom Angular components for each widget type used in the flow.
741
+ - **`sessionId?: string | null`**: Session ID for resuming an existing authentication session.
804
742
 
805
- ```typescript
806
- refresh(): Observable<void>;
807
- ```
743
+ **Outputs**
808
744
 
809
- - **`revoke()`**: Revokes the current session tokens.
745
+ - **`(login)`**: Emitted on successful authentication. Receives `IdTokenClaims | null`.
746
+ - **`(fallback)`**: Emitted when the native flow needs to fall back to redirect. Receives `FallbackError` with a fallback URL.
747
+ - **`(error)`**: Emitted when an error occurs during authentication.
748
+ - **`(globalMessage)`**: Emitted when the flow wants to display a global message (e.g. account lockout warning).
749
+ - **`(blockReady)`**: Emitted on flow state transitions. Receives `{ previousState: LoginFlowState; state: LoginFlowState }`. Useful for analytics and custom logging.
810
750
 
811
- ```typescript
812
- revoke(): Observable<void>;
813
- ```
751
+ ## Vulnerability Reporting
814
752
 
815
- - **`logout(options?: LogoutOptions)`**: Logs the user out using the specified options.
753
+ The [Guidelines for responsible disclosure](https://www.strivacity.com/report-a-security-issue) details the procedure for disclosing security issues. Please do not report security vulnerabilities on the public issue tracker.
816
754
 
817
- ```typescript
818
- logout(options?: LogoutOptions): Observable<void>;
819
- ```
755
+ ## License
820
756
 
821
- - **`handleCallback(url?: string)`**: Handles the authentication callback (e.g., after a redirect flow).
757
+ @strivacity/sdk-angular is available under the MIT License. See the [LICENSE](https://github.com/Strivacity/sdk-js/blob/main/LICENSE) file for more info.
822
758
 
823
- ```typescript
824
- handleCallback(url?: string): Observable<void>;
825
- ```
759
+ ## Contributing
826
760
 
827
- #### `StyLoginRenderer` component
828
-
829
- The `StyLoginRenderer` component is used in native mode to render the authentication UI directly within your application. It provides a fully customizable login experience using your own UI components.
830
-
831
- ```typescript
832
- StyLoginRenderer: Component<{
833
- params?: NativeParams;
834
- widgets?: PartialRecord<WidgetType, Component>;
835
- sessionId?: string | null;
836
- login?: EventEmitter<IdTokenClaims | null>;
837
- fallback?: EventEmitter<FallbackError>;
838
- error?: EventEmitter<any>;
839
- globalMessage?: EventEmitter<string>;
840
- blockReady?: EventEmitter<{ previousState: LoginFlowState; state: LoginFlowState }>;
841
- }>;
842
- ```
843
-
844
- **Properties**
845
-
846
- - **`params?: NativeParams`** (optional): Additional parameters to pass to the native login flow. These parameters can include custom configuration options for the authentication process.
847
-
848
- - **`widgets?: PartialRecord<WidgetType, Component>`** (optional): A collection of Angular components that define the UI widgets used in the authentication flow. Each widget type (input, button, layout, etc.) can be customized with your own components.
849
-
850
- - **`sessionId?: string | null`** (optional): The session ID for continuing an existing authentication session. This is typically extracted from URL parameters when returning from external identity providers.
851
-
852
- **Events**
853
-
854
- - **`(login)?: EventEmitter<IdTokenClaims | null>`** (optional): Event emitted when authentication is successful. Receives the ID token claims as a parameter.
855
-
856
- - **`(fallback)?: EventEmitter<FallbackError>`** (optional): Event emitted when the native flow cannot handle the authentication and needs to fall back to redirect mode. The error parameter contains the fallback URL.
857
-
858
- - **`(error)?: EventEmitter<any>`** (optional): Event emitted when an error occurs during the authentication process. Use this to handle and display error messages to users.
859
-
860
- - **`(globalMessage)?: EventEmitter<string>`** (optional): Event emitted when the authentication flow wants to display a global message to the user (e.g., account lockout warnings, validation messages).
861
-
862
- - **`(blockReady)?: EventEmitter<{ previousState: LoginFlowState; state: LoginFlowState }>`** (optional): Event emitted when the authentication flow transitions between states. Useful for tracking progress, implementing custom logging, or injecting analytics. Receives both the previous and current flow states.
863
-
864
- **Widget Types**
865
-
866
- The `widgets` input accepts the following widget types:
867
-
868
- - `checkbox`: For checkbox input fields
869
- - `date`: For date input fields
870
- - `input`: For text input fields
871
- - `layout`: For layout containers and form structure
872
- - `loading`: For loading indicators
873
- - `multiSelect`: For multi-select dropdown fields
874
- - `passcode`: For passcode input fields
875
- - `password`: For password input fields
876
- - `phone`: For phone number input fields
877
- - `select`: For single-select dropdown fields
878
- - `static`: For static text and display elements
879
- - `submit`: For form submission buttons
880
-
881
- Each widget component receives inputs specific to its type and function within the authentication flow.
882
-
883
- ## Links
884
-
885
- - [Example app](https://github.com/Strivacity/sdk-js/tree/main/apps/angular)
761
+ Please see our [contributing guide](https://github.com/Strivacity/sdk-js/blob/main/CONTRIBUTING.md).
886
762
 
887
763
  ## Migrating to v3.0
888
764
 
889
765
  ### Entry API Major Changes
890
766
 
891
- Strivacity SDK's `entry()` API now returns a structured object instead of a plain string. To see examples of these changes, check the apps folder in this repository.
767
+ Strivacity SDK's `entry()` API now returns a structured object instead of a plain string. Check the example above in the usage section for more details.