Adding Azure AD B2C Login to a Hybrid Mobile App Using Ionic Auth Connect
Published Aug 10 2020 11:27 PM 19.6K Views
Copper Contributor

Azure Active Directory B2C (Azure AD B2C) is a great way to enable secure authentication for your users across mobile and web -- from basic sign-in and sign-out, to profile management and more. 

 

While Azure AD B2C is designed to work well on any iOS or Android phone or tablet, integrating with any auth provider can be particularly tricky on a mobile device, particularly if you’re building a “hybrid” mobile app using something like Cordova or Capacitor. Issues like secure token storage, Man-In-The-Middle attacks, and timely security updates can be troublesome, and create risks if not handled properly.

 

That’s why the Ionic team designed Auth Connect. Ionic Auth Connect makes it easy to add secure authentication to any hybrid mobile app running on iOS, Android, or the web. Using a simple, powerful API, it handles logging in and/or registering a user with an authentication provider (such as Azure Active Directory) using industry-standard OAuth/OpenId Connect.

 

Getting Started

In this tutorial, we’ll add login/logout functionality to a basic Ionic app by integrating Ionic Auth Connect. There’s only a few steps required to implement Auth Connect with Azure AD B2C in an Ionic app: configure Azure AD B2C, install Auth Connect in an Ionic app, and configure Auth Connect to use Azure AD B2C.

 

To begin, clone this repository and follow along. The “start” folder contains the basic structure of the app that we’ll make changes to and the “completed” folder contains the finished app as a reference point if needed.

 

NOTE: An Ionic Native Enterprise Edition key is required in order to install and use the Ionic Auth Connect plugin. Ionic Native Enterprise features a library of Premier plugins and solutions that are fully supported and maintained by the Ionic team, with access to Ionic experts and a guaranteed response SLA to mission-critical app development. If you are interested in acquiring a key or learning more, please contact us here.

 

To see what Ionic Auth Connect looks like in action, view this short video. 

 

After cloning the code, do the following:

1. Install the Ionic CLI: 

 

 

 

 

npm install -g @ionic/cli

 

 

 

 

2. In a terminal, change directory into the “start” folder in the repository: 

 

 

 

 

cd demo-authconnect-azureb2c/start

 

 

 

 

3. Run npm install. NOTE: This will fail if an Ionic Native key hasn't been registered.

 

4. Run ionic serve to build and serve the app locally in a web browser.

 

The Reference App

The Ionic app is a modified version of a blank Angular starter project. It consists of two pages: the Home page displays the signed-in user's details (which will be retrieved from Azure AD B2C) and the Login page protects the Home page from unauthorized access. 

 

Azure Active Directory B2C Configuration

 

Before integrating Auth Connect into the Ionic app, you’ll need to get Azure Active Directory (AD) B2C up and running.

 

Note: For complete information on configuring Azure AD, consult the official B2C documentation which includes tutorials on creating a B2C tenant, registering applications, and more.

Create an Azure AD B2C Tenant

If you don't have one, create a new B2C tenant.

 

Register an Application

Sign into the Azure Portal then navigate to the Azure AD B2C service page.

 

Begin by creating a new Application under Manage - App registrations - New registration.

 

azureb2c-register-app.png

 

Give your app a new name, then select the Supported Account Types.

 

With that in hand, set the Redirect URI. Choose “Public client/native (mobile & desktop)” - we’ll add web support in a separate step. Then, fill in the text field value with your globally unique App Id, which is used both in the Azure configuration as well as the native mobile app’s configuration. Typically, this takes the form of company-AppName or reverse DNS style - com.company.app. Use the formula “uniqueId://page”. After the app user signs into Azure AD, this tells Auth Connect which page to redirect to in your app. While any page can be used, in this example we’ll use the Login page, such as com.company.app://login. Click the register button to create the app.

 

Add Web Platform

 

With the app created, navigate to Manage - Authentication. Click the “Add a Platform” button. Under Web applications, choose “single-page application.” 

 

Under Redirect URIs, specify a web URL. In this example, for local testing, we’ll use http://localhost:8100/ along with the name of your app's core login page (typically, login). 

 

Next, under Logout URL, specify a web URL to redirect to once the user has logged out of your app. Again, for local testing, specify https://localhost:8100/ along with the name of the logout page (typically logout).

 

Finally, under Implicit Grant, toggle “Access tokens.” Click the Configure button to save.

 

azureb2c-spa.png

 

 

Back on the Authentication page, look under the Single-page application settings. Click the “Add URI” button to add additional Redirect URIs, including those for other environments like staging or production. Click Save when ready.

 

azureb2c-web-redirecturis.png

 

 

Expose an API

 

Navigate to the “Expose an API” page. Click “Add a scope”, then for the Scope name, provide a value such as “user_impersonation.” For the display name and description fields, add details describing that this is for authenticating your users. Set the state to enabled then click the “Add scope” button.

 

Configure API Permissions

 

Next, we need to authorize our app so it can connect to Azure B2C and retrieve user profile information alongside login credentials. Navigate to the API Permissions page then click the “Add a permission” button. Under “Select an API”, choose “My APIs” then click the name of the B2C app we’re currently configuring. Next, select the “user_impersonation” permission (or whatever name you labeled it in the previous step) then click the “Add permissions” button.

 

Save the application, then click on the newly added permission row. Click the “Grant admin consent for [your organization name]” button then choose “Yes.”

azureb2c-api-permissions.png

Click on the “user_impersonation” permission row again to open the modal window, then click to copy the link that is displayed. Note this URL, because it will be used as part of Auth Connect’s “scopes” property later.

 

azureb2c-scopes-link.png

 

Create User Flows (Policies)

 

Create at least one User Flow, the series of pages that define the entire authentication experience for your app. At a minimum, create a Sign up and sign in flow. Once the User Flow has been created, select it from the User Flow list, then click "Run user flow" from the Overview tab. Note the URL at the top of the page, used to configure Auth Connect's Discovery URL property.

 

Azure AD B2C is now ready to use with Auth Connect.

Install Auth Connect

 

Auth Connect works on the web or on mobile. For deploying to mobile, we’ll use Capacitor, Ionic’s cross-platform native runtime for building native mobile and web apps, using JavaScript, HTML, and CSS, with one shared codebase. Learn more about the project and how to deploy this Ionic app to mobile here.

 

Adding Capacitor is easy:

 

 

 

 

ionic integrations enable capacitor

 

 

 

 

 

Run the following command to install the Auth Connect plugin. For the AUTH_URL_SCHEME variable, use the globally unique App Id (ex: com.company.app) you decided on when configuring the Azure AD app above.

 

 

 

 

npm install @ionic-enterprise/auth --variable AUTH_URL_SCHEME=com.company.app
npx cap sync

 

 

 

 

Configure Auth Connect

 

Configuring Auth Connect involves two steps: adding configuration details into the app from your Azure AD tenant and implementing login/logout functionality.

 

Azure Configuration Details

 

Since the Azure AD B2C app will support different values per environment (typically staging, QA, production, etc.) we can support that in the Ionic app using Angular’s environments. Open src/environments/environment.ts then add the following. We’ll begin with a web-based configuration since it’s easier to build and test locally in a browser:

 

 

 

 

 

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

export const azureWebConfig : IonicAuthOptions = {
  // the auth provider
  authConfig: 'azure',
  // The platform which we are running on
  platform: 'web',
  // client or application id for provider
  clientID: 'FILL_IN',
  // the discovery url for the provider
  // OpenID configuration
  discoveryUrl: 'FILL_IN',
  // the URI to redirect to after log in
  redirectUri: 'http://localhost:8100/login',
  // requested scopes from provider
  scope: 'openid offline_access email profile FILL_IN',
  // the URL to redirect to after log out
  logoutUrl: 'http://localhost:8100/login',
  // Show provider login in either current window or new tab
  implicitLogin: "CURRENT"
};

 

 

 

 

 

Some of these `IonicAuthOptions` values are unique and must be set based on the Azure AD app that we just created above:

 

* platform: Use “web” if running as a PWA or “capacitor” when the app is deployed as an iOS or Android app.

* clientID: Your app’s _Application (client) ID_, found on the Overview page. Example: cebbb0be-d578-4bbd-9712-4b0fe05c06aa

* redirectUri: The URI to redirect to after the user has logged in. Since we’re testing locally in a browser, use “http://localhost:8100/login” since this is what `ionic serve` runs on. 

* logoutUrl: The URI to redirect to after the user has logged out. Again, use “http://localhost:8100/”. 

 

The scope property is used to unlock access to protected resources, such as read/write permissions. There’s a variety of attributes available; an example looks like: “openid offline_access email profile”.

 

In addition to the values above, add the Full Scope Value link created earlier to the `scope` property. To find it in the Azure AD B2C portal, navigate to the “Expose an API” page then click on the Scope you defined earlier. In the modal window, copy the link that appears under “Scope name.” All together, it will look similar to this:

 

 

 

 

 

scope: 'openid offline_access email profile https://orgname.onmicrosoft.com/api/user_impersonation',

 

 

 

 

 

The discoveryUrl can be found by navigating to the main Azure AD B2C page -> Policies -> User flows -> [Select User Flow] -> Overview tab -> Run user flow button. The discovery link is at the top of the page and will look like the following format:

 

https://B2C-TENANT-NAME.b2clogin.com/B2C-TENANT-NAME.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=POLICY-NAME 

 

Where B2C-TENANT-NAME is your tenant name and the POLICY-NAME is the name of the User Flow created earlier.

 

The native mobile configuration is almost the same as the web. Make a copy of the web configuration then change the redirect and logout urls. Use the same AUTH_URL_SCHEME variable value (App Id) from when the Auth Connect plugin was installed. For example, “com.company.app://” plus the name of the Login page. Change the platform to “capacitor”:

 

 

 

 

 

export const azureNativeConfig : IonicAuthOptions = {
  platform: 'capacitor',
  redirectUrl: 'com.company.app://login',
  logoutUrl: 'com.company.app://logout'
	
  // snip - other variables
}

 

 

 

 

 

Create an Authentication Service for Login Functionality

 

With Azure AD environment configurations added to the Ionic app, we can now leverage them in an AuthenticationService class that encapsulates Azure AD and Ionic Auth Connect’s login functionality.

 

Generate this class using the ionic generate command:

 

 

 

 

 

ionic generate service services/authentication

 

 

 

 

 

Open up src/app/services/authentication.service.ts and import Auth Connect, RxJs (for tracking login status changes), and the Azure AD configuration objects we just created:

 

 

 

 

 

import { Injectable } from '@angular/core';
import { Platform } from '@ionic/angular';
import { IonicAuth } from '@ionic-enterprise/auth';
import { Subject, Observable } from 'rxjs';
import { azureNativeConfig, azureWebConfig } from '../../environments/environment';

 

 

 

 

 

Next, extend the IonicAuth class in order to gain access to Auth Connect’s functionality, and in the constructor, instantiate it with the proper Azure configuration object. Using Ionic’s Platform API, we can dynamically choose which configuration to use based on whether the app is running on the web or a mobile device.

 

 

 

 

 

export class AuthenticationService extends IonicAuth {
  constructor(platform: Platform) {
    // Determine whether to run on mobile or the web
    const selectedConfig = platform.is('hybrid') ? azureNativeConfig : azureWebConfig;
    super(selectedConfig);
}

 

 

 

 

 

Implementing login functionality is quite simple - we define our own login method then call Auth Connect’s login method.

 

 

 

 

 

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

 

 

 

 

 

Upon successful login, Auth Connect calls the `onLoginSuccess` event, which we can override here to run any additional logic we need. In this case, we can emit an RxJs event when the login status changes (either logged in or logged out) then react accordingly (direct the user into the app or back to the Login page). 

 

 

 

 

 

onLoginSuccess() {
    this._loginStatusChanged.next(true);
}

 

 

 

 

 

Define the status change observable right below the class definition:

 

 

 

 

 

 // Emit event when login status changes 
  private _loginStatusChanged: Subject<boolean>;

  get loginStatusChanged(): Observable<boolean> {
    return this._loginStatusChanged.asObservable();
  }

 

 

 

 

 

To detect and act on the login status changing, head over to `app.component.ts` in `src/app`. Import the AuthenticationService class, then subscribe to the status change observable:

 

 

 

 

 

import { AuthenticationService } from './services/authentication.service';

// snip

constructor(

    private auth: AuthenticationService,
    private navController: NavController,
    private platform: Platform
  ) {

    this.initializeApp();

    this.auth.loginStatusChanged.subscribe(authenticated => 
         this.handleAuthChange(authenticated));
  }

 

 

 

 

 

Next, add a method that inspects the status of the login attempt. If successful, redirect the user to the Home page, otherwise, remain on the Login page:

 

 

 

 

 

private handleAuthChange(authenticated: boolean) {
    if (authenticated) {
      this.navController.navigateRoot(['home']);
    } else {
      this.navController.navigateRoot(['login']);
    }
  }

 

 

 

 

 

The last step is easy: leveraging the AuthenticationService from the Login page (`src/app/login/login.page.ts`). First, add a click handler to the Login button:

 

 

 

 

 

<ion-button (click)="login()" strong shape="round">
   Log in
</ion-button>

 

 

 

 

 

Next, add a new method to call the AuthenticationService’s login method:

 

 

 

 

 

async login() {
  await this.authService.login();
}

 

 

 

 

 

Just one last step required. When running as a web app, the user will be redirected to the Azure AD sign-in page. After successful sign-in, they’ll be sent back to the Ionic app and since this is a “fresh” load of the page, we need to pass the access token along to Auth Connect. To do so, pass the browser’s url to Auth Connect’s `handleCallback` function:

 

 

 

 

 

async ngOnInit() {
    if (window.location.hash) {
        await this.authService.handleCallback(window.location.href);
    }
}

 

 

 

 

 

Once handleCallback completes, Auth Connect will call `onLoginSuccess()` in the AuthenticationService class, which triggers the login status change event, ultimately permitting the user access to the Home page.

 

That’s it! Click the Login button in the browser, sign in using your Azure AD B2C credentials, then you should be redirected to the Home app.

 

View Azure AD User Details

 

Logging in is nice, but what if we took it one step further by displaying some of the Azure AD user’s profile details on the Home page?

 

Back over in the AuthenticationService, declare a new method to retrieve the user’s profile info from Azure. Access all information via Auth Connect’s `getIdToken` function:

 

 

 

 

 

async getUserInfo() {
    const idToken = await this.getIdToken();
    if (!idToken) {
      return;
    }

    let email = idToken.email;

    if (idToken.emails instanceof Array) {
      email = idToken.emails[0];
    }

    return {
      id: idToken.sub,
      email: email,
      firstName: idToken.given_name,
      lastName: idToken.family_name,
      picture: "assets/user-placeholder.jpg"
    };
  }

 

 

 

 

 

Next, over in the Home page (`src/app/home/home.page.ts`), make the call to `getUserInfo` when the page loads:

 

 

 

 

 

user: any;

constructor(private authService: AuthenticationService) { }

async ngOnInit() {
    this.user = await this.authService.getUserInfo();
}

 

 

 

 

 

To complete this, update the Home page’s HTML template so that it now displays the user’s profile info:

 

 

 

 

 

<ion-content>
  <div class="ion-padding">
    <div align="center" *ngIf="user">
      <ion-avatar>
        <img src="{{ user.picture }}">
      </ion-avatar>

      <p>{{ user.firstName}} {{ user.lastName }}</p> 
      <p>{{ user.email }}</p>
    </div>

    <ion-button expand="block" (click)="logout();" style="margin-top: 50px">Log out</ion-button>
  </div>
</ion-content>

 

 

 

 

 

If you’re still running `ionic serve`, save all files, then the page should reload, displaying your Azure AD user profile details.

Implementing Log Out

 

The last step is to add logout functionality. Since we’re already in the Home page code, add a new function that calls Auth Connect’s `logout` function directly:

 

 

 

 

 

async logout() {
    await this.authService.logout();
  }

 

 

 

 

 

 

Back over in AuthenticationService, implement Auth Connect’s “onLogout” event, which fires once it has successfully logged out the current user. All the app needs to do is fire the login status changed event, passing “false” to indicate that the user is no longer logged in:

 

 

 

 

 

onLogout() {
    this._loginStatusChanged.next(false);
  }

 

 

 

 

 

 

Recall that this event will be caught over in `app.component.ts`, and since “authenticated” is now false, the user will be redirected to the Login page:

 

 

 

 

 

private handleAuthChange(authenticated: boolean) {
    if (authenticated) {
      this.navController.navigateRoot(['home']);
    } else {
      this.navController.navigateRoot(['login']);
    }
  }

 

 

 

 

 

Reload the page, click the Logout button, and you should be signed out then redirected to the Login page. 

 

What's Next?

 

In just a few steps, we added Azure AD B2C authentication to an Ionic app, with complete login and logout functionality. With Auth Connect now in place, there are many paths to go from here. You can further tweak the Azure AD user experience (such as customizing the user interface) or begin testing Auth Connect in a native app right away.

 

About Ionic Auth Connect

 

Auth Connect is built and maintained by the Ionic team. Ionic makes tools and services that empower web developers to deliver stunning native mobile and web applications, using the web tools, libraries, and frameworks that they know and love. Our cross-platform native runtime, Capacitor, provides a secure way to deliver web-based applications on a mobile device. When coupled with Ionic’s Auth Connect solution, implementing single sign-on in web applications is even easier.

 

Happy app building!

1 Comment
Version history
Last update:
‎Aug 11 2020 04:12 PM
Updated by: