Skip to content

Commit da9e978

Browse files
committed
update readme
1 parent 89c7f30 commit da9e978

File tree

4 files changed

+121
-88
lines changed

4 files changed

+121
-88
lines changed

1-Authentication/2-sign-in-b2c/README.md

Lines changed: 102 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,19 @@ MSAL Angular is a wrapper around MSAL.js (i.e. *msal-browser*). As such, many of
180180

181181
### Configuration
182182

183-
You can initialize your application in several ways, for instance, by loading the configuration parameters from another server. See [Configuration options](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/configuration.md) for more information.
183+
You can initialize your application in several ways, for instance, by loading the configuration parameters from another server. See [configuration options](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/configuration.md) for more information.
184184

185-
In the sample, authentication parameters reside in [auth-config.ts](./SPA/src/app/auth-config.ts). These parameters then are used for initializing MSAL Angular configuration options in [app.module.ts](./SPA/src/app/app.module.ts).
185+
In the sample, authentication parameters reside in [auth-config.ts](./SPA/src/app/auth-config.ts). These parameters are used for initializing MSAL Angular configuration options in [app.module.ts](./SPA/src/app/app.module.ts).
186186

187187
### Sign-in
188188

189189
**MSAL Angular** exposes 3 login APIs: `loginPopup()`, `loginRedirect()` and `ssoSilent()`. First, setup your default interaction type in [app.module.ts](./SPA/src/app/app.module.ts):
190190

191191
```typescript
192192
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
193-
return {
194-
interactionType: InteractionType.Redirect,
195-
};
193+
return {
194+
interactionType: InteractionType.Redirect,
195+
};
196196
}
197197
```
198198

@@ -201,35 +201,35 @@ Then, define a login method in [app.component.ts](./SPA/src/app/app.component.ts
201201
```typescript
202202
export class AppComponent implements OnInit {
203203

204-
constructor(
204+
constructor(
205205
@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
206206
private authService: MsalService,
207207
private msalBroadcastService: MsalBroadcastService
208-
) {}
208+
) {}
209209

210-
ngOnInit(): void {
210+
ngOnInit(): void {
211211

212-
login() {
212+
login() {
213213
if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
214-
if (this.msalGuardConfig.authRequest) {
215-
this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
216-
.subscribe((response: AuthenticationResult) => {
217-
this.authService.instance.setActiveAccount(response.account);
218-
});
214+
if (this.msalGuardConfig.authRequest) {
215+
this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
216+
.subscribe((response: AuthenticationResult) => {
217+
this.authService.instance.setActiveAccount(response.account);
218+
});
219219
} else {
220-
this.authService.loginPopup()
221-
.subscribe((response: AuthenticationResult) => {
222-
this.authService.instance.setActiveAccount(response.account);
223-
});
224-
}
220+
this.authService.loginPopup()
221+
.subscribe((response: AuthenticationResult) => {
222+
this.authService.instance.setActiveAccount(response.account);
223+
});
224+
}
225225
} else {
226-
if (this.msalGuardConfig.authRequest) {
227-
this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
228-
} else {
229-
this.authService.loginRedirect();
230-
}
226+
if (this.msalGuardConfig.authRequest) {
227+
this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
228+
} else {
229+
this.authService.loginRedirect();
230+
}
231+
}
231232
}
232-
}
233233
}
234234
```
235235
@@ -238,26 +238,26 @@ If you already have a session that exists with the authentication server, you ca
238238
```typescript
239239
export class AppComponent implements OnInit {
240240
241-
constructor(
242-
private authService: MsalService,
243-
) {}
241+
constructor(
242+
private authService: MsalService,
243+
) {}
244244
245-
ngOnInit(): void {
245+
ngOnInit(): void {
246246
const silentRequest: SsoSilentRequest = {
247-
scopes: ["User.Read"],
248-
loginHint: "user@contoso.com"
247+
scopes: ["User.Read"],
248+
loginHint: "user@contoso.com"
249249
}
250250
251251
this.authService.ssoSilent(silentRequest)
252-
.subscribe({
253-
next: (result: AuthenticationResult) => {
254-
console.log("SsoSilent succeeded!");
255-
},
256-
error: (error) => {
257-
this.authService.loginRedirect();
258-
}
259-
});
260-
}
252+
.subscribe({
253+
next: (result: AuthenticationResult) => {
254+
console.log("SsoSilent succeeded!");
255+
},
256+
error: (error) => {
257+
this.authService.loginRedirect();
258+
}
259+
});
260+
}
261261
}
262262
```
263263

@@ -269,22 +269,22 @@ The sign-out clears the user's single sign-on session with **Azure AD B2C**, but
269269

270270
### ID Token Validation
271271

272-
When you receive an [ID token](https://docs.microsoft.com/azure/active-directory/develop/id-tokens) directly from the IdP on a secure channel (e.g. HTTPS), such is the case with SPAs, there’s no need to validate it. If you were to do it, you would validate it by asking the same server that gave you the ID token to give you the keys needed to validate it, which renders it pointless, as if one is compromised so is the other.
272+
When you receive an [ID token](https://learn.microsoft.com/azure/active-directory-b2c/tokens-overview) directly from the IdP on a secure channel (e.g. HTTPS), such is the case with SPAs, there’s no need to validate it. If you were to do it, you would validate it by asking the same server that gave you the ID token to give you the keys needed to validate it, which renders it pointless, as if one is compromised so is the other.
273273

274274
### Securing Routes
275275

276-
You can add authentication to secure specific routes in your application by just adding `canActivate: [MsalGuard]` to your route definition. It can be added at the parent or child routes. This ensures that the user must be signed-in to access the secured route.
276+
You can add authentication to secure specific routes in your application by just adding `canActivate: [MsalGuard]` to your route definition. It can be added at the parent or child routes. This ensures that the user must be signed-in to access the secured route. See [app-routing.module.ts](./SPA/src/app/app-routing.module.ts) for more.
277277

278278
```typescript
279-
const routes: Routes = [
280-
{
281-
path: 'guarded',
282-
component: GuardedComponent,
283-
canActivate: [
284-
MsalGuard
285-
]
286-
}
287-
]
279+
const routes: Routes = [
280+
{
281+
path: 'guarded',
282+
component: GuardedComponent,
283+
canActivate: [
284+
MsalGuard
285+
]
286+
}
287+
]
288288
```
289289

290290
### Events API
@@ -297,25 +297,25 @@ Using the event API, you can register an event callback that will do something w
297297
```typescript
298298
export class HomeComponent implements OnInit {
299299
300-
private readonly _destroying$ = new Subject<void>();
301-
302-
constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
300+
private readonly _destroying$ = new Subject<void>();
301+
302+
constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
303+
304+
ngOnInit(): void {
305+
this.msalBroadcastService.msalSubject$
306+
.pipe(
307+
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
308+
takeUntil(this._destroying$)
309+
)
310+
.subscribe((result: EventMessage) => {
311+
// do something with the result, such as accessing ID token
312+
});
313+
}
303314
304-
ngOnInit(): void {
305-
this.msalBroadcastService.msalSubject$
306-
.pipe(
307-
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
308-
takeUntil(this._destroying$)
309-
)
310-
.subscribe((result: EventMessage) => {
311-
// do something with the result, such as accessing ID token
312-
});
313-
}
314-
315-
ngOnDestroy(): void {
316-
this._destroying$.next(undefined);
317-
this._destroying$.complete();
318-
}
315+
ngOnDestroy(): void {
316+
this._destroying$.next(undefined);
317+
this._destroying$.complete();
318+
}
319319
}
320320
```
321321

@@ -329,20 +329,46 @@ This user-flow allows your users to sign-in to your application if the user has
329329

330330
* **Edit Profile**
331331

332-
When a user selects the **Edit Profile** button on the navigation bar, we simply initiate a sign-in flow:
332+
This user-flow allows your users to update their profile information. When a user selects the **Edit Profile** button on the navigation bar, we simply initiate a sign-in flow against the edit profile user-flow authority:
333333

334334
```typescript
335-
editProfile() {
335+
// in app.component.ts
336+
337+
editProfile() {
336338
let editProfileFlowRequest = {
337-
scopes: ["openid"],
338-
authority: b2cPolicies.authorities.editProfile.authority,
339+
scopes: ["openid"],
340+
authority: b2cPolicies.authorities.editProfile.authority,
339341
};
340-
342+
341343
this.login(editProfileFlowRequest);
342-
}
344+
}
343345
```
344346

345-
Like password reset, edit profile user-flow requires users to sign-out and sign-in again.
347+
* **Password Reset**
348+
349+
Password reset user-flow allows your users to change their password in case they forgot it or etc. When a user selects the **forgot my password** link on Azure AD B2C sing-in page, the B2C service will throw an error to the application, of which the application must catch and handle it by initiating a login against the password-reset user-flow authority.
350+
351+
```typescript
352+
// in app.component.ts
353+
354+
this.msalBroadcastService.msalSubject$
355+
.pipe(
356+
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_FAILURE || msg.eventType === EventType.ACQUIRE_TOKEN_FAILURE),
357+
takeUntil(this._destroying$)
358+
)
359+
.subscribe((result: EventMessage) => {
360+
// Checking for the forgot password error. Learn more about B2C error codes at
361+
// https://learn.microsoft.com/azure/active-directory-b2c/error-codes
362+
if (result.error && result.error.message.indexOf('AADB2C90118') > -1) {
363+
let resetPasswordFlowRequest: RedirectRequest | PopupRequest = {
364+
authority: b2cPolicies.authorities.resetPassword.authority,
365+
scopes: [],
366+
};
367+
368+
this.login(resetPasswordFlowRequest);
369+
};
370+
});
371+
```
346372

347373
## Next Steps
348374

1-Authentication/2-sign-in-b2c/SPA/karma.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module.exports = function (config) {
3737
colors: true,
3838
logLevel: config.LOG_INFO,
3939
autoWatch: true,
40-
browsers: ['ChromeHeadlessCI'],
40+
browsers: ['Chrome', 'ChromeHeadless', 'ChromeHeadlessCI'],
4141
customLaunchers: {
4242
ChromeHeadlessCI: {
4343
base: 'ChromeHeadless',

1-Authentication/2-sign-in-b2c/SPA/src/app/app.module.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { BrowserModule } from '@angular/platform-browser';
22
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
33
import { NgModule } from '@angular/core';
44
import { FormsModule } from '@angular/forms';
5-
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
5+
import { HttpClientModule } from '@angular/common/http';
66

77
import { IPublicClientApplication, PublicClientApplication, InteractionType } from '@azure/msal-browser';
88
import {
9-
MsalGuard, MsalInterceptor, MsalBroadcastService, MsalService,
9+
MsalGuard, MsalBroadcastService, MsalService,
1010
MSAL_GUARD_CONFIG, MSAL_INSTANCE, MsalGuardConfiguration, MsalRedirectComponent
1111
} from '@azure/msal-angular';
1212

@@ -21,7 +21,7 @@ import { AppRoutingModule } from './app-routing.module';
2121
import { AppComponent } from './app.component';
2222
import { HomeComponent } from './home/home.component';
2323

24-
import { msalConfig } from './auth-config';
24+
import { loginRequest, msalConfig } from './auth-config';
2525

2626
/**
2727
* Here we pass the configuration parameters to create an MSAL instance.
@@ -38,6 +38,7 @@ export function MSALInstanceFactory(): IPublicClientApplication {
3838
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
3939
return {
4040
interactionType: InteractionType.Redirect,
41+
authRequest: loginRequest
4142
};
4243
}
4344

@@ -57,14 +58,9 @@ export function MSALGuardConfigFactory(): MsalGuardConfiguration {
5758
MatIconModule,
5859
MatTableModule,
5960
HttpClientModule,
60-
FormsModule,
61+
FormsModule
6162
],
6263
providers: [
63-
{
64-
provide: HTTP_INTERCEPTORS,
65-
useClass: MsalInterceptor,
66-
multi: true
67-
},
6864
{
6965
provide: MSAL_INSTANCE,
7066
useFactory: MSALInstanceFactory
@@ -77,6 +73,6 @@ export function MSALGuardConfigFactory(): MsalGuardConfiguration {
7773
MsalGuard,
7874
MsalBroadcastService
7975
],
80-
bootstrap: [AppComponent, MsalRedirectComponent]
76+
bootstrap: [AppComponent, MsalRedirectComponent],
8177
})
8278
export class AppModule { }

1-Authentication/2-sign-in-b2c/SPA/src/app/auth-config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,20 @@ export const msalConfig: Configuration = {
6666
}
6767
}
6868

69+
/**
70+
* Scopes you add here will be prompted for user consent during sign-in.
71+
* By default, MSAL.js will add OIDC scopes (openid, profile) to any login request.
72+
* For more information about OIDC scopes, visit:
73+
* https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
74+
*/
75+
export const loginRequest = {
76+
scopes: []
77+
}
78+
6979
/**
7080
* An optional silentRequest object can be used to achieve silent SSO
71-
* between applications by providing a "login_hint" property.
81+
* between applications by providing a "loginHint" property. For more, visit:
82+
* https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-js-sso#sso-between-different-apps
7283
*/
7384
export const silentRequest = {
7485
scopes: [],

0 commit comments

Comments
 (0)