Skip to main content
Version: 3.x

Auth Connect Angular

This tutorial follows on from the Installation and auth provider guides (Auth0, AWS Cognito, Azure AD B2C or Okta) and integrates functionality for login, logout and the user's authenticated state in your Ionic Angular application.

Build Time Options

The configuration settings (such as redirectUri) of your auth provider will change depending on your target environment (e.g. production, staging or development). Settings should not be hard coded in your application and a good practice is to use Angular's Environment files to allow these settings to be set at build time.

Revisiting our AuthenticationService class, the IonicAuth object has been moved to environment.ts:

import { IonicAuth, IonicAuthOptions } from '@ionic-enterprise/auth';
import { authOptions } from '../../environments/environment';

export class AuthenticationService extends IonicAuth {

constructor() {
super(authOptions);
}
}

In the projects environment.ts file we add:

import { IonicAuthOptions } from "@ionic-enterprise/auth";

export const authOptions: IonicAuthOptions = {
authConfig: 'FILL_IN',
platform: 'FILL_IN',
clientID: 'FILL_IN',
discoveryUrl: 'FILL_IN',
redirectUri: 'FILL_IN',
scope: 'FILL_IN',
logoutUrl: 'FILL_IN',
iosWebView: 'FILL_IN'
};

To keep development settings separate from production you should apply similar code to your environment.prod.ts file using the settings for the production instance of your auth provider.

Run Time Options

Authentication options will also change at runtime depending on where your application is run (eg Native vs Web). In the AuthenticationService class we can dynamically initialize options in the constructor:

import { Platform } from '@ionic/angular';
import { nativeIonicAuthOptions, webIonicAuthOptions } from '../../environments/environment';
...
constructor(platform: Platform) {
super(platform.is('hybrid') ? nativeIonicAuthOptions : webIonicAuthOptions);
}

Here we have taken our authOptions object and refactored to provide 2 objects for native and web.

Login

Your application is now ready to trigger a login flow. Lets create a button for this:

<ion-button (click)="login()">Sign In</ion-button>

And call the login method of IonicAuth:

import { AuthenticationService } from '../authentication/authentication.service';
...
constructor(private authenticationService: AuthenticationService) { }

async login(): Promise<void> {
await this.authenticationService.login();
}

You can now run your application and test the login flow. It is worth noting that the login page for your auth provider will open in its own window (and if already logged in will open and close immediately) and once a successful login is achieved will return a token using the redirectUri property back to your application.

note

A common mistake is an incorrectly set redirectUri so be sure to test for development (such as when run via ionic serve) and production (where Auth Connect depends on the deep linking setup in your project) to ensure the login page closes successfully.

Logout

Similar to login, test your logout flow by adding a button:

<ion-button (click)="logout()">Sign Out</ion-button>

Followed by calling the logout method of IonicAuth:

  async logout(): Promise<void> {
this.authenticationService.logout();
}

Authenticated?

Whilst Auth Connect provides a isAuthenticated method to determine whether a user is authenticated or not, your application will likely have multiple places that need to reactively change based on this state. We can extend our authenticationService to emit events whenever the authentication state changes:

import { Injectable, NgZone } from '@angular/core';
import { IonicAuth } from '@ionic-enterprise/auth';
import { Platform } from '@ionic/angular';
import { BehaviorSubject, Observable } from 'rxjs';
import { nativeIonicAuthOptions, webIonicAuthOptions } from '../../environments/environment';

@Injectable({
providedIn: 'root'
})
export class AuthenticationService extends IonicAuth {
private authenticationChange: BehaviorSubject<boolean> = new BehaviorSubject(false);
public authenticationChange$: Observable<boolean>;

constructor(platform: Platform, private ngZone: NgZone) {
super(platform.is('hybrid') ? nativeIonicAuthOptions : webIonicAuthOptions);
this.authenticationChange$ = this.authenticationChange.asObservable();
this.isAuthenticated().then((authenticated) => { this.onAuthChange(authenticated); });
}

public async onLoginSuccess(): Promise<void> {
this.onAuthChange(true);
}

public async onLogout(): Promise<void> {
this.onAuthChange(false);
}

private async onAuthChange(isAuthenticated: boolean): Promise<void> {
this.ngZone.run(() => {
this.authenticationChange.next(isAuthenticated);
});
}
}
note

The events from IonicAuth run outside of Angular's change detection system so to get correct behavior when binding to a view we need to ensure that NgZone is run.

We can now update our buttons to show/hide based on our authenticated state:

<ion-button [hidden]="(authenticationChange$ | async)" (click)="login()">Sign In</ion-button>
<ion-button [hidden]="!(authenticationChange$ | async)" (click)="logout()">Sign Out</ion-button>

In the code behind the view:

import { Observable } from 'rxjs';
...
public authenticationChange$: Observable<boolean>;

constructor(private authenticationService: AuthenticationService) {
this.authenticationChange$ = authenticationService.authenticationChange$;
}

Next Steps

Your application is now functional but there are some recommended next steps such as: