-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(oauth2): add types to handlers, allow better inheritance, ad… (
#1065) * refactor(oauth2): add types to handlers, allow better inheritance, add examples Closes #922 * feat(oauth2): add Azure example to docs
- Loading branch information
1 parent
e3e524b
commit be1e754
Showing
9 changed files
with
326 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Configuring Azure OAuth2 with Nebular Auth | ||
|
||
Using `NbOAuth2AuthStrategy` gives possibility to configure authentication with a lot of 3rd party authentication providers, such as Azure in our example. | ||
There is no need in any backend implementation, as [OAuth2](https://tools.ietf.org/html/rfc6749) protocol enables completely server-less authentication flow as one of the options. | ||
|
||
## Complete example | ||
|
||
A complete code example could be found on [GitHub](https://github.com/akveo/nebular/tree/master/src/playground/azure). | ||
And here the playground example available to play around with [Azure OAuth2 Nebular Example](/example/azure). | ||
|
||
<hr> | ||
|
||
## Related Articles | ||
|
||
- [NbAuthService](/docs/auth/nbauthservice) | ||
- [NbTokenService](/docs/auth/nbtokenservice) | ||
- Receiving [user token after authentication](/docs/auth/getting-user-token) | ||
- [NbOAuth2AuthStrategy](/docs/auth/nboauth2authstrategy) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { of } from 'rxjs'; | ||
|
||
import { map, switchMap, catchError } from 'rxjs/operators'; | ||
|
||
import { | ||
NbOAuth2AuthStrategy, | ||
NbOAuth2ResponseType, | ||
NbAuthOAuth2JWTToken, | ||
NbOAuth2AuthStrategyOptions, | ||
NbAuthStrategyClass, | ||
NbAuthResult, | ||
NbAuthIllegalTokenError, | ||
} from '@nebular/auth'; | ||
|
||
|
||
// Create new token for Azure auth so it returns id_token instead of access_token | ||
export class NbAuthAzureToken extends NbAuthOAuth2JWTToken { | ||
|
||
// let's rename it to exclude name clashes | ||
static NAME = 'nb:auth:azure:token'; | ||
|
||
getValue(): string { | ||
return this.token.id_token; | ||
} | ||
} | ||
|
||
@Injectable() | ||
export class NbAzureADB2CAuthStrategy extends NbOAuth2AuthStrategy { | ||
|
||
// we need this method for strategy setup | ||
static setup(options: NbOAuth2AuthStrategyOptions): [NbAuthStrategyClass, NbOAuth2AuthStrategyOptions] { | ||
return [NbAzureADB2CAuthStrategy, options]; | ||
} | ||
|
||
protected redirectResultHandlers = { | ||
[NbOAuth2ResponseType.CODE]: () => { | ||
return of(this.route.snapshot.queryParams).pipe( | ||
switchMap((params: any) => { | ||
if (params.code) { | ||
return this.requestToken(params.code); | ||
} | ||
|
||
return of( | ||
new NbAuthResult( | ||
false, | ||
params, | ||
this.getOption('redirect.failure'), | ||
this.getOption('defaultErrors'), | ||
[], | ||
)); | ||
}), | ||
); | ||
}, | ||
id_token: () => { | ||
const module = 'authorize'; | ||
const requireValidToken = this.getOption(`${module}.requireValidToken`); | ||
return of(this.route.snapshot.fragment).pipe( | ||
map(fragment => this.parseHashAsQueryParams(fragment)), | ||
map((params: any) => { | ||
if (!params.error) { | ||
return new NbAuthResult( | ||
true, | ||
params, | ||
this.getOption('redirect.success'), | ||
[], | ||
this.getOption('defaultMessages'), | ||
this.createToken(params, requireValidToken)); | ||
} | ||
return new NbAuthResult( | ||
false, | ||
params, | ||
this.getOption('redirect.failure'), | ||
this.getOption('defaultErrors'), | ||
[], | ||
); | ||
}), | ||
catchError(err => { | ||
const errors = []; | ||
if (err instanceof NbAuthIllegalTokenError) { | ||
errors.push(err.message); | ||
} else { | ||
errors.push('Something went wrong.'); | ||
} | ||
return of( | ||
new NbAuthResult( | ||
false, | ||
err, | ||
this.getOption('redirect.failure'), | ||
errors, | ||
)); | ||
}), | ||
); | ||
}, | ||
}; | ||
|
||
|
||
protected redirectResults: any = { | ||
[NbOAuth2ResponseType.CODE]: () => of(null), | ||
|
||
id_token: () => { | ||
return of(this.route.snapshot.fragment).pipe( | ||
map(fragment => this.parseHashAsQueryParams(fragment)), | ||
map((params: any) => !!(params && (params.id_token || params.error))), | ||
); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { Component, OnDestroy } from '@angular/core'; | ||
import { NbAuthResult, NbAuthService } from '@nebular/auth'; | ||
import { Router } from '@angular/router'; | ||
import { takeWhile } from 'rxjs/operators'; | ||
|
||
@Component({ | ||
selector: 'nb-playground-azure-callback', | ||
template: ` | ||
<nb-layout> | ||
<nb-layout-column>Authenticating...</nb-layout-column> | ||
</nb-layout> | ||
`, | ||
}) | ||
export class NbAzureCallbackComponent implements OnDestroy { | ||
|
||
alive = true; | ||
|
||
constructor(private authService: NbAuthService, private router: Router) { | ||
this.authService.authenticate('azure') | ||
.pipe(takeWhile(() => this.alive)) | ||
.subscribe((authResult: NbAuthResult) => { | ||
if (authResult.isSuccess() && authResult.getRedirect()) { | ||
this.router.navigateByUrl(authResult.getRedirect()); | ||
} | ||
}); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.alive = false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { Component, OnDestroy } from '@angular/core'; | ||
import { NbAuthResult, NbAuthService } from '@nebular/auth'; | ||
import { takeWhile } from 'rxjs/operators'; | ||
import { NbAuthAzureToken } from './azure-adb2c-auth-strategy'; | ||
|
||
@Component({ | ||
selector: 'nb-playground-azure', | ||
template: ` | ||
<nb-layout> | ||
<nb-layout-column> | ||
<nb-card> | ||
<nb-card-body> | ||
<p>Current User Authenticated: {{ !!token }}</p> | ||
<p>Current User Token: {{ token|json }}</p> | ||
<button nbButton status="success" *ngIf="!token" (click)="login()">Sign In with Azure</button> | ||
<button nbButton status="warning" *ngIf="token" (click)="logout()">Sign Out</button> | ||
</nb-card-body> | ||
</nb-card> | ||
</nb-layout-column> | ||
</nb-layout> | ||
`, | ||
}) | ||
export class NbAzureLoginComponent implements OnDestroy { | ||
|
||
token: NbAuthAzureToken; | ||
|
||
alive = true; | ||
|
||
constructor(private authService: NbAuthService) { | ||
this.authService.onTokenChange() | ||
.pipe(takeWhile(() => this.alive)) | ||
.subscribe((token: NbAuthAzureToken) => { | ||
this.token = null; | ||
if (token && token.isValid()) { | ||
this.token = token; | ||
} | ||
}); | ||
} | ||
|
||
login() { | ||
this.authService.authenticate('azure') | ||
.pipe(takeWhile(() => this.alive)) | ||
.subscribe((authResult: NbAuthResult) => { | ||
}); | ||
} | ||
|
||
logout() { | ||
this.authService.logout('azure') | ||
.pipe(takeWhile(() => this.alive)) | ||
.subscribe((authResult: NbAuthResult) => { | ||
}); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.alive = false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/** | ||
* @license | ||
* Copyright Akveo. All Rights Reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { CommonModule } from '@angular/common'; | ||
import { NgModule } from '@angular/core'; | ||
import { FormsModule } from '@angular/forms'; | ||
import { RouterModule } from '@angular/router'; | ||
import { HttpClientModule } from '@angular/common/http'; | ||
|
||
import { | ||
NbCardModule, | ||
NbLayoutModule, | ||
} from '@nebular/theme'; | ||
|
||
import { NbAuthModule } from '@nebular/auth'; | ||
|
||
import { NbAzureLoginComponent } from './azure-login.component'; | ||
import { NbAzureCallbackComponent } from './azure-callback.component'; | ||
import { NbAuthAzureToken, NbAzureADB2CAuthStrategy } from './azure-adb2c-auth-strategy'; | ||
|
||
|
||
@NgModule({ | ||
imports: [ | ||
CommonModule, | ||
FormsModule, | ||
HttpClientModule, | ||
RouterModule, | ||
RouterModule.forChild([ | ||
{ | ||
path: '', | ||
component: NbAzureLoginComponent, | ||
}, | ||
{ | ||
path: 'callback', | ||
component: NbAzureCallbackComponent, | ||
}, | ||
]), | ||
|
||
NbAuthModule.forRoot({ | ||
strategies: [ | ||
NbAzureADB2CAuthStrategy.setup({ | ||
name: 'azure', | ||
clientId: 'bde728e2-2809-4ff1-bc9c-7fcb23800ebe', | ||
clientSecret: '', | ||
authorize: { | ||
endpoint: 'https://login.microsoftonline.com/01513fd2-16a0-453b-9fa0-c9089bfa023e/oauth2/authorize', | ||
responseType: 'id_token', | ||
scope: 'openid', | ||
redirectUri: 'https://akveo.github.io/nebular/example/azure/callback', | ||
params: { | ||
p: 'b2c_1_nebular', | ||
}, | ||
}, | ||
token: { | ||
class: NbAuthAzureToken, | ||
}, | ||
redirect: { | ||
success: '/example/azure', | ||
}, | ||
}), | ||
], | ||
}), | ||
|
||
NbCardModule, | ||
NbLayoutModule, | ||
], | ||
declarations: [ | ||
NbAzureLoginComponent, | ||
NbAzureCallbackComponent, | ||
], | ||
providers: [ | ||
NbAzureADB2CAuthStrategy, | ||
], | ||
}) | ||
export class NbAzurePlaygroundModule { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters