is logged in {{ loggedIn }}
Email: {{ profile.email}}
Name: {{ profile.nickname}}
Kapil Panchal - July 07, 2021
Listening is fun too.
Straighten your back and cherish with coffee - PLAY !
Auth0 is a versatile, drop-in solution to add authentication and authorization services to the applications. Auth0 is simple to implement and an adaptable authentication and authorization platform.
Auth0 is a secure service that ensures authentication and authorization functionality when implemented in your application. It works based on tokens and uses different identity providers. It includes several platforms as well as social networks.
When you build your solution to authenticate and authorize users, it can cost you money, time, and risk. To avoid these, we should use Auth0 in our application.
NgRx is a framework for creating reactive applications in Angular. NgRx provides libraries for the following:
NgRx is an open-source library that provides reactive state management for Angular applications. NgRx provides a way to preserve data in your Angular application as a single source of truth which is inspired by Redux.
NgRx uses streams to communicate with a data store, this data store connects to your components and services and ultimately simplifies the complete method of data management in your Angular application. Rather than injecting services every place and managing communication between them, NgRx manages your application from only one source. Instead of working with individual components, you can work with in terms of its overall state using NgRx.
The first step is to add the angular application in Auth0.
Go to https://auth0.com/ to create an account in Auth0. You will see the dashboard of Auth0 as shown in the following image.
Click on create an application to integrate auth0 in the Angular application.
After clicking on create application from the dashboard, you will be navigated to the following page. On this Page Write the name of your application and click on Single Page Web Applications as we are creating an Angular application.
Once this is created, you will see the basic information like Name, Client ID, Domain, Client Server as well as application properties, Application URLs, ID token, etc. As we know out Angular will run on the domain HTTP(s)://localhost:4200 locally, so add these URLs into the correct fields of auth0. We have added both http://localhost:4200 and https://localhost:4200 in the fields as shown in the below image, so in the case where we need to switch to HTTPS, we do not face any problems.
From the same page, we will need values of Client ID and Domain to place in our angular application.
Now, we can create our Angular application with the following command:
ng new Auth0withNgrx
After creating an angular application, we will install Angular helpers from Auth0:
npm install @auth0/auth0-angular
Auth0 is a third-party library, so we will create abstraction for it. We will add a file called auth.service.ts.
auth.service.ts:import { Injectable } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class AuthenticationService { constructor(public authService: AuthService) {} get isLoggedIn$(): Observable{ return this.authService.isAuthenticated$; } getToken$(): Observable { return this.authService.getAccessTokenSilently(); } get user$(): Observable { return this.authService.user$; } login(): void { this.authService.loginWithRedirect(); } logout(): void { this.authService.logout({ returnTo: document.location.origin }); } }
We must include AuthModule form @auth0/auth0-angular in the app.module.ts file. Here we will include the values of Client ID and Domain that we found while creating application in Basic Information in Auth0 dashboard.
app.module.ts:import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AuthModule } from '@auth0/auth0-angular'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { authReducer } from './store/auth.reducer'; import { AuthEffects } from './store/auth.effects'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, StoreModule.forRoot({ auth: authReducer }), EffectsModule.forRoot([AuthEffects]), AuthModule.forRoot({ domain: '', clientId: ' ', redirectUri: window.location.origin, }), ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
To add NgRx in our application, we need to include dependencies @ngrx/store and @ngrx/effects by executing the following commands:
ng add @ngrx/store@latest
ng add @ngrx/effects@latest
After adding dependencies in our application, we will create a separate folder for placing NgRx related files in it.
We will create a folder named “store” under the app and place the following four NgRx related files in that folder.
We will create a file called auth.actions.ts under the store folder for adding actions. We will add the action to trigger the login for calling login as well as a corresponding action for completeness called loginComplete. Same for logout and logoutComplete. We will create an action to trigger when the auth0 redirects back to our angular application for telling the state that it must be changed.
auth.actions.ts:import { createAction, props } from '@ngrx/store'; export const checkAuth = createAction('[Auth] checkAuth'); export const login = createAction('[Auth] login'); export const loginComplete = createAction( '[Auth] loginComplete', props<{ profile: any; isLoggedIn: boolean }>() ); export const logout = createAction('[Auth] logout'); export const logoutComplete = createAction('[Auth] logoutComplete');
The state of our application will be stored in an object called auth with the values – userProfile and idLoggedIn.
{ auth: { isLoggedIn, userProfile } }
We will create a reducer file called auth.reducer.ts under the store folder to add our state as an interface.
auth.reducer.ts:import { Action, createReducer, on } from '@ngrx/store'; import * as authActions from './auth.actions'; export interface AuthState { userProfile: any; isLoggedIn: boolean; } export const initialState: AuthState = { userProfile: null, isLoggedIn: false, }; const authReducerInternal = createReducer( initialState, on(authActions.loginComplete, (state, { profile, isLoggedIn }) => { return { ...state, userProfile: profile, isLoggedIn, }; }), on(authActions.logoutComplete, (state, {}) => { return { ...state, userProfile: null, isLoggedIn: false, }; }) ); export function authReducer( state: AuthState | undefined, action: Action ): AuthState { return authReducerInternal(state, action); }
The AuthState represents the value the auth property has in our state. The reducer only handles anything that goes on inside of the auth property.
We have set the initialState and create the reducer to pass the initialState. We must add state manipulation when a specific action comes in.
We will add the profile we received if the login is completed with the action loginComplete, and also set the isLoggedIn. We will reset the userProfile to null and isLoggedIn to false when the action logoutComplete is thrown.
We will use effects for the asynchronous work to do when we are trying to manipulate the state after async actions have finished. We will create auth.effects.ts file for implementing effects.
The following 3 are actions to listen to:
The login, the logout and the checkAuth action.
import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { combineLatest, of } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; import { AuthenticationService } from '../auth.service'; import * as fromAuthActions from './auth.actions'; @Injectable() export class AuthEffects { constructor( private actions$: Actions, private authService: AuthenticationService ) {} login$ = createEffect( () => this.actions$.pipe( ofType(fromAuthActions.login), tap(() => this.authService.login()) ), { dispatch: false } ); checkAuth$ = createEffect(() => this.actions$.pipe( ofType(fromAuthActions.checkAuth), switchMap(() => combineLatest([this.authService.isLoggedIn$, this.authService.user$]) ), switchMap(([isLoggedIn, profile]) => { if (isLoggedIn) { return of(fromAuthActions.loginComplete({ profile, isLoggedIn })); } return of(fromAuthActions.logoutComplete()); }) ) ); logout$ = createEffect(() => this.actions$.pipe( ofType(fromAuthActions.logout), tap(() => this.authService.logout()), switchMap(() => of(fromAuthActions.logoutComplete())) ) ); }
The login effect will call the authService.login() action and won’t dispatch any other actions then.
The logout action will call the authService.logout() method and will return the logoutComplete.
When we will get redirected from Auth0 to our app again, we will throw the checkAuth action. We will collect the latest information got updated by the service of Auth0 and add it to our state. We have collected isLoggedIn$ and user$ properties and update the state with it. If isLoggedIn is true-which should be the case after the redirect- then we can return a loginComplete action, otherwise, we will reset the state with a logoutComplete action
We will build selectors to make the consumption in components clear which we want from the state and provide it.
We will create a selector for the isLoggedIn and the user-profile property as well as the auth property from the state object.
import { createFeatureSelector, createSelector } from '@ngrx/store'; import { AuthState } from './auth.reducer'; export const getAuthFeatureState = createFeatureSelector('auth'); export const selectCurrentUserProfile = createSelector( getAuthFeatureState, (state: AuthState) => state.userProfile ); export const selectIsLoggedIn = createSelector( getAuthFeatureState, (state: AuthState) => state.isLoggedIn );
To consume the values in the state of selectors, the component will consume the selectors. And it dispatches the action checkAuth() when the checkAuth() is loaded to update the information in the state.
It also provides two methods for login and logout.
import { Component, OnInit } from '@angular/core'; import { select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { checkAuth, login, logout } from './store/auth.actions'; import { selectCurrentUserProfile, selectIsLoggedIn } from './store/auth.selectors'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ title = 'Auth0withNgrx'; loggedIn$: Observable| undefined; profile$: Observable | undefined; constructor(private store: Store ) {} ngOnInit() { this.loggedIn$ = this.store.pipe(select(selectIsLoggedIn)); this.profile$ = this.store.pipe(select(selectCurrentUserProfile)); this.store.dispatch(checkAuth()); } logout() { this.store.dispatch(logout()); } login() { this.store.dispatch(login()); } } /any>
We will use the information in the template as needed.
We will display the UserProfile, Name, and Email of the user who logged in.
is logged in {{ loggedIn }}
Email: {{ profile.email}}Name: {{ profile.nickname}}
When we run the project, we will see the following output:
When we click on this button, we will be redirected to the page provided by Auth0.
You need to sign up first either using your email id or your google account. Then you can log in to the system by entering valid credentials and it will redirect you to the information page as follows:
Build Your Agile Team
12 December 2024Kapil Panchal
There is a principle behind every business. “If you don’t keep track of essentials, you won’t get clear direction, eventually causing your company to stumble.” To manage this scenario,...
03 December 2024Vinod Satapara - Technical Director
Do you know when geospatial analysis took traction in healthcare? It was when John Snow, a London-based physician, used it to analyze the spread of cholera, which ultimately proved...
29 November 2024Kapil Panchal
One interesting aspect you truly love about Power BI, as a CTO, is how it lets you step back and see the bigger picture of your business. Isn’t it? Without getting bogged down in minute...