-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
24b249f
commit 9ffae06
Showing
18 changed files
with
202 additions
and
11,356 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,16 @@ | ||
import { TestBed } from '@angular/core/testing'; | ||
|
||
import { AuthService } from './auth.service'; | ||
|
||
describe('AuthService', () => { | ||
let service: AuthService; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({}); | ||
service = TestBed.inject(AuthService); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(service).toBeTruthy(); | ||
}); | ||
}); |
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,126 @@ | ||
import { Injectable } from '@angular/core'; | ||
import createAuth0Client from '@auth0/auth0-spa-js'; | ||
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client'; | ||
import { from, of, Observable, BehaviorSubject, combineLatest, throwError } from 'rxjs'; | ||
import { tap, catchError, concatMap, shareReplay } from 'rxjs/operators'; | ||
import { Router } from '@angular/router'; | ||
|
||
@Injectable({ | ||
providedIn: 'root' | ||
}) | ||
export class AuthService { | ||
// Create an observable of Auth0 instance of client | ||
auth0Client$ = (from( | ||
createAuth0Client({ | ||
domain: "YOUR_DOMAIN", | ||
client_id: "YOUR_CLIENT_ID", | ||
redirect_uri: `${window.location.origin}` | ||
}) | ||
) as Observable<Auth0Client>).pipe( | ||
shareReplay(1), // Every subscription receives the same shared value | ||
catchError(err => throwError(err)) | ||
); | ||
// Define observables for SDK methods that return promises by default | ||
// For each Auth0 SDK method, first ensure the client instance is ready | ||
// concatMap: Using the client instance, call SDK method; SDK returns a promise | ||
// from: Convert that resulting promise into an observable | ||
isAuthenticated$ = this.auth0Client$.pipe( | ||
concatMap((client: Auth0Client) => from(client.isAuthenticated())), | ||
tap(res => this.loggedIn = res) | ||
); | ||
handleRedirectCallback$ = this.auth0Client$.pipe( | ||
concatMap((client: Auth0Client) => from(client.handleRedirectCallback())) | ||
); | ||
// Create subject and public observable of user profile data | ||
private userProfileSubject$ = new BehaviorSubject<any>(null); | ||
userProfile$ = this.userProfileSubject$.asObservable(); | ||
// Create a local property for login status | ||
loggedIn: boolean = null; | ||
|
||
constructor(private router: Router) { | ||
// On initial load, check authentication state with authorization server | ||
// Set up local auth streams if user is already authenticated | ||
this.localAuthSetup(); | ||
// Handle redirect from Auth0 login | ||
this.handleAuthCallback(); | ||
} | ||
|
||
// When calling, options can be passed if desired | ||
// https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser | ||
getUser$(options?): Observable<any> { | ||
return this.auth0Client$.pipe( | ||
concatMap((client: Auth0Client) => from(client.getUser(options))), | ||
tap(user => this.userProfileSubject$.next(user)) | ||
); | ||
} | ||
|
||
private localAuthSetup() { | ||
// This should only be called on app initialization | ||
// Set up local authentication streams | ||
const checkAuth$ = this.isAuthenticated$.pipe( | ||
concatMap((loggedIn: boolean) => { | ||
if (loggedIn) { | ||
// If authenticated, get user and set in app | ||
// NOTE: you could pass options here if needed | ||
return this.getUser$(); | ||
} | ||
// If not authenticated, return stream that emits 'false' | ||
return of(loggedIn); | ||
}) | ||
); | ||
checkAuth$.subscribe(); | ||
} | ||
|
||
login(redirectPath: string = '/') { | ||
// A desired redirect path can be passed to login method | ||
// (e.g., from a route guard) | ||
// Ensure Auth0 client instance exists | ||
this.auth0Client$.subscribe((client: Auth0Client) => { | ||
// Call method to log in | ||
client.loginWithRedirect({ | ||
redirect_uri: `${window.location.origin}`, | ||
appState: { target: redirectPath } | ||
}); | ||
}); | ||
} | ||
|
||
private handleAuthCallback() { | ||
// Call when app reloads after user logs in with Auth0 | ||
const params = window.location.search; | ||
if (params.includes('code=') && params.includes('state=')) { | ||
let targetRoute: string; // Path to redirect to after login processsed | ||
const authComplete$ = this.handleRedirectCallback$.pipe( | ||
// Have client, now call method to handle auth callback redirect | ||
tap(cbRes => { | ||
// Get and set target redirect route from callback results | ||
targetRoute = cbRes.appState && cbRes.appState.target ? cbRes.appState.target : '/'; | ||
}), | ||
concatMap(() => { | ||
// Redirect callback complete; get user and login status | ||
return combineLatest([ | ||
this.getUser$(), | ||
this.isAuthenticated$ | ||
]); | ||
}) | ||
); | ||
// Subscribe to authentication completion observable | ||
// Response will be an array of user and login status | ||
authComplete$.subscribe(([user, loggedIn]) => { | ||
// Redirect to target route after callback processing | ||
this.router.navigate([targetRoute]); | ||
}); | ||
} | ||
} | ||
|
||
logout() { | ||
// Ensure Auth0 client instance exists | ||
this.auth0Client$.subscribe((client: Auth0Client) => { | ||
// Call method to log out | ||
client.logout({ | ||
client_id: "YOUR_CLIENT_ID", | ||
returnTo: `${window.location.origin}` | ||
}); | ||
}); | ||
} | ||
|
||
} |
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
Oops, something went wrong.