Real-World Angular Series, Part 2a: Authentication

  • Open this file and customize the following code with your own Auth0 client and API information:

    Authentication logic on the front-end will be handled with an authentication service.

  • The constructor checks the current authentication status upon app initialization.
  • The method authorizes the authentication request with Auth0 using the auth config variables.
  • The method uses Auth0’s method callback to get the user’s profile ( ) and set the session ( ) by saving the tokens, expiration, and profile to local storage and calling so that any components in the app are informed that the user is now authenticated.
  • In order to use the methods and properties anywhere in our app, we need to add the service to the array in our :

    The authentication service’s method must be called in the constructor so it will run on initialization of our app:

    Next, we’ll create a Callback component.

We continue creating our real-world Angular application by learning how to implement front-end authentication into our app using web tokens and an API.

@c0deNinja: Real-World Angular Series, Part 2a: Authentication #AngularJS #JavaScript

Part 1a and Part 1b of this tutorial covered how to set up the cloud-hosted MongoDB database, Node server, and front-end for our real-world Angular application.

The second installment in the series covers authentication, authorization, feature planning, and data modeling.

Let’s pick up right where we left off last time. We’ve built the main layout for our app. Now it’s time to add an authentication feature. Our app’s basic authentication should include:

First, let’s install a few dependencies. We need the auth0-js package to interface with our Auth0 account. The angular2-jwt package provides helpers to authorize HTTP requests. Install both packages with npm from the project root:

, but the app will be deployed on the Node server eventually, and in production, it will run on a reverse proxy. We’ll need to make sure our development environment doesn’t break our production environment and vice versa.

configuration wherever we need to detect and use these URIs.

Open this file and customize the following code with your own Auth0 client and API information:

authentication service. Let’s generate the boilerplate for a new service with the CLI:

file and add the necessary code to our authentication service:

// src/app/auth/auth.service.ts import { Injectable } from ‘@angular/core’; import { Router } from ‘@angular/router’; import { BehaviorSubject } from ‘rxjs/BehaviorSubject’; import { AUTH_CONFIG } from ‘./auth.config’; import * as auth0 from ‘auth0-js’; // Avoid name not found warnings declare var auth0: any; @Injectable() export class AuthService { // Create Auth0 web auth instance auth0 = new auth0.WebAuth({ clientID: AUTH_CONFIG.CLIENT_ID, domain: AUTH_CONFIG.CLIENT_DOMAIN, responseType: ‘token id_token’, redirectUri: AUTH_CONFIG.REDIRECT, audience: AUTH_CONFIG.AUDIENCE, scope: AUTH_CONFIG.SCOPE }); userProfile: any; // Create a stream of logged in status to communicate throughout app loggedIn: boolean; loggedIn$ = new BehaviorSubject(this.loggedIn); constructor(private router: Router) { // If authenticated, set local profile property // and update login status subject. // If not authenticated but there are still items // in localStorage, log out. const lsProfile = localStorage.getItem(‘profile’); if (this.tokenValid) { this.userProfile = JSON.parse(lsProfile); this.setLoggedIn(true); } else if (!this.tokenValid && lsProfile) { this.logout(); } } setLoggedIn(value: boolean) { // Update login status subject this.loggedIn$.next(value); this.loggedIn = value; } login() { // Auth0 authorize request this.auth0.authorize(); } handleAuth() { // When Auth0 hash parsed, get profile this.auth0.parseHash((err, authResult) => { if (authResult && authResult.accessToken && authResult.idToken) { window.location.hash = ”; this._getProfile(authResult); } else if (err) { console.error(`Error authenticating: ${err.error}`); } this.router.navigate([‘/’]); }); } private _getProfile(authResult) { // Use access token to retrieve user’s profile and set session this.auth0.client.userInfo(authResult.accessToken, (err, profile) => { if (profile) { this._setSession(authResult, profile); } else if (err) { console.error(`Error authenticating: ${err.error}`); } }); } private _setSession(authResult, profile) { // Save session data and update login status subject const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + Date.now()); // Set tokens and expiration in localStorage and props localStorage.setItem(‘access_token’, authResult.accessToken); localStorage.setItem(‘id_token’, authResult.idToken); localStorage.setItem(‘expires_at’, expiresAt); localStorage.setItem(‘profile’, JSON.stringify(profile)); this.userProfile = profile; // Update login status in loggedIn$ stream this.setLoggedIn(true); } logout() { // Ensure all auth items removed from localStorage localStorage.removeItem(‘access_token’); localStorage.removeItem(‘id_token’); localStorage.removeItem(‘profile’); localStorage.removeItem(‘authRedirect’); // Reset local properties, update loggedIn$ stream this.userProfile = undefined; this.setLoggedIn(false); // Return to homepage this.router.navigate([‘/’]); } get tokenValid(): boolean { // Check if current time is past access token’s expiration const expiresAt = JSON.parse(localStorage.getItem(‘expires_at’)); return Date.now() < expiresAt; } } instance. is used to provide a stream of authentication status events that we can subscribe to anywhere in the app. method is executed to clear any expired session data. method authorizes the authentication request with Auth0 using the auth config variables. An Auth0 hosted Lock instance will be shown to the user and they can then log in. Note: If it’s the user’s first visit to our app and our callback is on localhost, they’ll also be presented with a consent screen where they can grant access to our API. A first party client on a non-localhost domain would be highly trusted, so the consent dialog would not be presented in this case. You can modify this by editing your Auth0 Dashboard API Settings. Look for the “Allow Skipping User Consent” toggle. so that any components in the app are informed that the user is now authenticated. accessor to check whether the current DateTime is less than the token expiration DateTime. constructor so it will run on initialization of our app: Next, we’ll create a Callback component. This is where the app is redirected after authentication. This component simply shows a loading message until hash parsing is completed and the Angular app redirects back to the homepage. Let’s generate this component with the Angular CLI: , like so: Now we have the logic necessary to authenticate users, but we still need a way for them to log in and out in the UI. Let’s add this in the Header component. file: and declare it in the constructor function. template: property from our authentication service to determine if the user is logged in to show or hide the appropriate markup. If the user is not logged in, we’ll show a “Log In” link. If they’re already authenticated, we’ll show their name and a link to log out. file: We can now log into our app! Try it out in the browser. Once logged in, you should see your name and a link to log out in the upper right corner of the header. You should also be able to close the browser and reopen it to find your session has persisted (unless enough time has passed for the token to expire). factory using angular2-jwt. with the following command: file and add: header. like so: as a method to make secure requests.

Real-World Angular Series, Part 2a: Authentication

You might also like More from author

Comments are closed, but trackbacks and pingbacks are open.