@strivacity/sdk-angular 3.0.0-rc.0 → 3.0.1
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/CHANGELOG.md +32 -0
- package/README.md +244 -368
- package/dist/README.md +244 -368
- package/dist/fesm2022/strivacity-sdk-angular.mjs +4 -0
- package/dist/fesm2022/strivacity-sdk-angular.mjs.map +1 -1
- package/dist/lib/services/auth.service.d.ts +2 -2
- package/package.json +2 -2
package/dist/README.md
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# @strivacity/sdk-angular
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
28
|
+
### Initialization
|
|
19
29
|
|
|
20
|
-
#### NgModule
|
|
30
|
+
#### NgModule apps
|
|
21
31
|
|
|
22
|
-
`
|
|
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'
|
|
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
|
|
56
|
+
#### Standalone apps
|
|
47
57
|
|
|
48
|
-
`
|
|
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'
|
|
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
|
-
|
|
78
|
+
Inject `StrivacityAuthService` into any component to access authentication state:
|
|
68
79
|
|
|
69
|
-
|
|
80
|
+
```ts
|
|
81
|
+
import { Component } from '@angular/core';
|
|
82
|
+
import { StrivacityAuthService } from '@strivacity/sdk-angular';
|
|
70
83
|
|
|
71
|
-
|
|
84
|
+
@Component({ standalone: true, selector: 'app-root', template: '' })
|
|
85
|
+
export class AppComponent {
|
|
86
|
+
constructor(private strivacityAuthService: StrivacityAuthService) {}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
### Redirect / Popup mode
|
|
74
91
|
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
+
#### Callback page example
|
|
106
123
|
|
|
107
|
-
The callback page handles the response from the identity provider
|
|
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
|
-
|
|
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
|
-
|
|
183
|
-
</dt>
|
|
184
|
-
<dd>
|
|
185
|
-
|
|
186
|
-
</dd>
|
|
187
|
-
<dt>
|
|
188
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
345
|
+
### Native mode
|
|
369
346
|
|
|
370
|
-
|
|
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
|
-
|
|
349
|
+
The example widgets use SCSS for styling and Luxon for date handling:
|
|
373
350
|
|
|
374
|
-
|
|
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
|
-
|
|
388
|
+
#### Login page example
|
|
409
389
|
|
|
410
|
-
|
|
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` and optionally `language` from the URL on load, cleans up the URL, and passes them 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. When a `language` parameter is present it overrides `uiLocales` to display the authentication UI in the specified language.
|
|
415
391
|
|
|
416
392
|
```html
|
|
417
393
|
<!-- login.component.html -->
|
|
418
|
-
<
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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 {
|
|
436
|
-
import { widgets } from '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
583
|
+
### Embedded mode
|
|
600
584
|
|
|
601
|
-
|
|
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
|
-
|
|
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
|
-
|
|
593
|
+
void import(`${environment.issuer}/assets/components/bundle.js`);
|
|
606
594
|
|
|
607
|
-
|
|
595
|
+
bootstrapApplication(AppComponent, appConfig);
|
|
596
|
+
```
|
|
608
597
|
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
import {
|
|
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
|
-
@
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
|
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
|
-
|
|
640
|
+
## Logging
|
|
632
641
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
699
|
+
### `StrivacityAuthService`
|
|
719
700
|
|
|
720
|
-
|
|
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
|
-
- **`
|
|
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
|
|
708
|
+
**Session type**
|
|
735
709
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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()`**:
|
|
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
|
-
|
|
788
|
-
isAuthenticated(): Observable<boolean>;
|
|
789
|
-
```
|
|
729
|
+
---
|
|
790
730
|
|
|
791
|
-
|
|
731
|
+
### `StyLoginRenderer` component
|
|
792
732
|
|
|
793
|
-
|
|
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
|
-
-
|
|
735
|
+
**Selector:** `sty-login-renderer`
|
|
798
736
|
|
|
799
|
-
|
|
800
|
-
register(options?: RegisterOptions): Observable<void>;
|
|
801
|
-
```
|
|
737
|
+
**Inputs**
|
|
802
738
|
|
|
803
|
-
- **`
|
|
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
|
-
|
|
806
|
-
refresh(): Observable<void>;
|
|
807
|
-
```
|
|
743
|
+
**Outputs**
|
|
808
744
|
|
|
809
|
-
- **`
|
|
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
|
-
|
|
812
|
-
revoke(): Observable<void>;
|
|
813
|
-
```
|
|
751
|
+
## Vulnerability Reporting
|
|
814
752
|
|
|
815
|
-
|
|
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
|
-
|
|
818
|
-
logout(options?: LogoutOptions): Observable<void>;
|
|
819
|
-
```
|
|
755
|
+
## License
|
|
820
756
|
|
|
821
|
-
-
|
|
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
|
-
|
|
824
|
-
handleCallback(url?: string): Observable<void>;
|
|
825
|
-
```
|
|
759
|
+
## Contributing
|
|
826
760
|
|
|
827
|
-
|
|
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.
|
|
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.
|