Skip to main content
Version: 5.0

Upgrading Auth Connect

note

Upgrading from version 2? This same guide will still apply, however some of the described APIs from version 3 may differ slightly from what you might have.

Overview

Auth Connect 5 provides an updated API that improves the flexibility with how you choose to integrate it with your application. While these changes may appear large at first, as we walk through this guide, you'll see that most API calls in your application map over exactly how you currently use Auth Connect.

Stateless Architecture

The biggest change you'll see with Auth Connect 5 is that the library has moved to a stateless architecture. This means that instead of Auth Connect managing how all your tokens and provider info are stored, it instead leaves that up to your application to determine. Let's look at a simple example of this.

In Auth Connect 3 and earlier, setting up the provider in Angular and calling login might look something similar to the following:


_25
import { IonicAuth } from '@ionic-enterprise/auth';
_25
_25
export class MyAuthentication extends IonicAuth {
_25
constructor() {
_25
super({
_25
authConfig: 'auth0',
_25
platform: 'capacitor',
_25
clientID: 'my-magic-id',
_25
discoveryUrl: 'https://example.com/.well-known/openid-configuration',
_25
redirectUri: 'com.example.myapp://login',
_25
logoutUrl: 'com.example.myapp://logout'
_25
})
_25
}
_25
_25
async login() {
_25
try {
_25
await super.login();
_25
const accessToken = await this.getAccessToken();
_25
const refreshToken = await this.getRefreshToken();
_25
const idToken = await this.getIdToken();
_25
} catch (e) {
_25
console.error('Login Failed', e);
_25
}
_25
}
_25
}

You'll notice that calling login had no return and threw errors that you might catch if anything went wrong. If the method resolves how you would expect it to, then you make subsequent calls to get the various points of data returned by the provided. Auth Connect also handled storing these internally for you automatically. You could override this by providing a tokenStorageProvider as part of the constructor configuration, but by default, it stored everything for you in localStorage.

The following example provides the same functionality in an Angular application, but using the new Auth Connect 5 APIs:


_21
import { Auth0Provider, AuthConnect } from '@ionic-enterprise/auth';
_21
_21
export class MyAuthentication {
_21
private readonly provider = new Auth0Provider();
_21
private readonly options: ProviderOptions = {
_21
clientID: 'my-magic-id',
_21
audience: 'https://example.com/',
_21
discoveryUrl: 'https://example.com/.well-known/openid-configuration',
_21
redirectUri: 'com.example.myapp://login',
_21
logoutUrl: 'com.example.myapp://logout'
_21
}
_21
_21
async login() {
_21
try {
_21
const result = await AuthConnect.login(this.provider, this.options);
_21
const { accessToken, refreshToken, idToken } = result;
_21
} catch (e) {
_21
console.log('Login Failed', e);
_21
}
_21
}
_21
}

The first thing to notice is that the component that is calling into the service that provides the functionality from Auth Connect hasn't needed to change at all. All of the refactoring we've done is all done inside the service. This should make it easy to update and application that has properly abstracted their authentication into a single location.

Next, and likely most importantly, you'll notice that the call to login now returns a result, whereas before it returned void on success. This result object that is returned contains everything Auth Connect knows about the current authentication state. Any tokens you may have are stored here, information about your provider is stored here, expiration of your tokens, ect. Your application should store in information securely using a solution such as Identity Vault. For more information related to storing your tokens, check out securing your tokens. This result object is serializable, and should be stored and retrieved to restore a user's authentication session.

Capacitor-First Architecture

The new version of Auth Connect has been rebuilt from the ground up on Capacitor. This means for the best experience, we definitely recommend building your application with Capacitor, however, Auth Connect 5 does still maintain support for Cordova projects as well through a new required plugin for Cordova projects, @capacitor/plugin-cordova-compat. This plugin is required for Auth Connect to work with Cordova projects, and should be installed as part of your project's setup.

Upgrade Steps

The following steps will describe generally how you would upgrade a project using Auth Connection 3 to the latest version of Auth Connect 5. While your project may differ in structure from the example here, the general principles should still apply. If you have any questions or need help migrating your project, please reach out to your support contact.

Install the latest version

Capacitor


_10
npm install @ionic-enterprise/auth@latest

The previous version of Auth Connect required changes to the AndroidManifest.xml file in your Android project. This has been removed in Auth Connect 5 in favor of adding code to your build.gradle file.

Remove the following code from your AndroidManifest.xml file:


_11
<intent-filter>
_11
<data android:scheme="$AUTH_URL_SCHEME"/>
_11
<action android:name="android.intent.action.VIEW"/>
_11
<category android:name="android.intent.category.DEFAULT"/>
_11
<category android:name="android.intent.category.BROWSABLE"/>
_11
</intent-filter>
_11
<intent-filter>
_11
<action android:name="android.intent.action.SEND"/>
_11
<category android:name="android.intent.category.DEFAULT"/>
_11
<data android:mimeType="text/*"/>
_11
</intent-filter>

Add the following code to your build.gradle file:


_10
android {
_10
...
_10
defaultConfig {
_10
...
_10
manifestPlaceholders = [
_10
'AUTH_URL_SCHEME': 'mycustomscheme' /// CHANGE THIS TO YOUR CUSTOM AUTH SCHEME
_10
]
_10
}
_10
}

Cordova


_10
ionic cordova plugin remove @ionic-enterprise/auth
_10
ionic cordova plugin add @capacitor/plugin-cordova-compat
_10
ionic cordova plugin add @ionic-enterprise/auth --variable AUTH_URL_SCHEME='mycustomscheme'

note

If you are currently building using Cordova, we recommend that you upgrade to Capacitor. Our Visual Studio Code extension makes the process simple! [LINK NEEDED, pending PR merge]

Configure your provider

Your provider is now represented as a class as opposed to a string like it was in version 3.

Before


_10
const providerConfig = {
_10
authConfig: 'auth0'
_10
}

After


_10
const provider = new Auth0Provider();

If you're using a provider without support built into Auth Connect, it's now incredibly easy to tell Auth Connect how to integrate with them by extending the AuthProvider class and implementing the required methods. Full documentation on how to do this can be found in the Custom Providers section of the documentation.


_21
import { AuthProvider, Manifest, ProviderOptions, AuthConnectConfig, Params } from '@ionic-enterprise/auth';
_21
_21
export class MyCustomProvider extends AuthProvider {
_21
async authorizeRequest(
_21
manifest: Manifest,
_21
options: ProviderOptions,
_21
config: Pick<
_21
AuthConnectConfig,
_21
'ios' | 'android' | 'web' | 'platform' | 'logLevel'
_21
>
_21
) {
_21
const url = 'https://example.com/oauth2/authorize';
_21
const params: Params = {};
_21
params['client_id'] = '123';
_21
_21
return {
_21
url,
_21
params
_21
};
_21
}
_21
}

If you need to add some additional parameters to any of the requests, you can simply extend your existing provider to do so.


_21
import { AuthProvider, Manifest, ProviderOptions, AuthConnectConfig, Params } from '@ionic-enterprise/auth';
_21
_21
export class MyCustomProvider extends Auth0Provider {
_21
async authorizeRequest(
_21
manifest: Manifest,
_21
options: ProviderOptions,
_21
config: Pick<
_21
AuthConnectConfig,
_21
'ios' | 'android' | 'web' | 'platform' | 'logLevel'
_21
>
_21
) {
_21
const { url, params } = await super.authorizeRequest(manifest, options, config);
_21
return {
_21
url,
_21
params: {
_21
...params,
_21
['my-custom']: 'param'
_21
}
_21
}
_21
}
_21
}

Configuring your token storage provider

You should decide how you plan to store your authentication result, including all your tokens, inside your application. If you were originally using the default storage mechanism with Auth Connect, you were using localStorage. We recommend using Identity Vault to store your tokens and protect them with the biometric hardware available on phones. If you had previously configured a tokenStorageProvider for Auth Connect, this same interface can work well for your application. Something simple might look as follows:


_11
import { AuthResult } from '@ionic-enterprise/auth';
_11
_11
export async function storeAuthResult(data: AuthResult) {
_11
await identityVault.setValue('my-unique-key', JSON.stringify(data));
_11
}
_11
_11
export async function getAuthResult(): AuthResult | null {
_11
const data = await identityVault.getValue('my-unique-key');
_11
if (!data) return null;
_11
return JSON.parse(data);
_11
}

Initialize Auth Connect

Now that you have your provider and token storage provider configured, you can initialize Auth Connect. Auth Connect provides a static setup(options) method that will configure the behavior of the library within your application. This method should be called before any other Auth Connect methods are called. Subsequent calls to this method are ignored.


_10
await AuthConnect.setup({
_10
platform: 'capacitor',
_10
logLevel: 'DEBUG',
_10
ios: {},
_10
android: {},
_10
...
_10
})

Convert Auth Connect to stateless

Now we have everything in place to do the bulk of the work. In this step, you should work through your code, translating any calls to auth connect with the new updated methods. In most cases, the change should be nearly 1-to-1, with the only main difference being that the new functions accept the AuthResult object as a parameter now.

Before


_23
class MyAuth extends IonicAuth {
_23
constructor() {
_23
super({
_23
...options
_23
})
_23
}
_23
_23
async login() {
_23
await super.login();
_23
}
_23
_23
async logout() {
_23
await super.logout();
_23
}
_23
_23
async getAccessToken() {
_23
await super.getAccessToken();
_23
}
_23
_23
async getRefreshToken() {
_23
await super.getRefreshToken();
_23
}
_23
}

After


_29
class MyAuth {
_29
private provider = new Auth0Provider();
_29
private options = {
_29
...options
_29
}
_29
private result: AuthResult | null;
_29
_29
async login() {
_29
this.result = await AuthConnect.login(this.provider, this.options);
_29
}
_29
_29
async logout() {
_29
if (!this.result) return;
_29
await AuthConnect.logout(this.provider, this.result);
_29
}
_29
_29
// This no longer needs to be async, but you might leave it if your code
_29
// is already expecting it, or perhaps you pull from an async storage
_29
// mechanism if not held in memory.
_29
async getAccessToken() {
_29
if (!this.result) return null;
_29
return this.result.accessToken;
_29
}
_29
_29
async getRefreshToken() {
_29
if (!this.result) return null;
_29
return this.result.refreshToken;
_29
}
_29
}

note

Auth Connect 3 took a class based approach that is no longer required for Auth Connect 5. Working in fameworks such as React you may find that a larger refactor away from the class based structure can significantly improve your code. If you're interested in learning more about this, check out the Getting Started guides for your framework for choice, such as for React.

For refernce on any of the additional methods that Auth Connect provides, see the reference document that describes all the methods available on the class.

Handling IsAuthenticated checks

You may have noticed at this point, that one method in particular that is missing in the new version of Auth Connect, isAuthenticated(). In previous versions, Auth Connect shipped with this method that provided a convenient default behavior for checking if a user was authenticated. However, this previous method only covered the "happy path", meaning that it didn't handle edge cases well, such as a no network situation. This often caught teams using Auth Connect off guard and wasn't something that would be noticed until an app was already deployed in production where users often find themselves outside the happy path.

Moving forward, we very highly recommend teams use the various other methods provided by Auth Connect to build out their own logic of what it means for a user "to be authenticated" in your system, as this definition can vary wildly. We would recommend reading through the isAuthenticated guide documentation to learn more about the considerations involved when building out this check. If you want to continue to use the old logic, the snippet below should replicate the old functionality.


_29
async function isAuthenticated() {
_29
// Use your own provider here
_29
const provider: AuthProvider = new Auth0Provider();
_29
try {
_29
const authResult = await identityVault.getValue('my-auth-result');
_29
// If no id token, the login is invalid
_29
const { idToken } = authResult;
_29
if (!idToken) throw new Error('No ID Token');
_29
_29
// If token is not expired, user is currently authenticated
_29
const expired = await AuthConnect.isAccessTokenExpired(authResult);
_29
if (!expired) return true;
_29
_29
// Token is expired, so try to refresh the session, will throw if fails
_29
const newAuthResult = await AuthConnect.refreshSession(provider, authResult);
_29
/**
_29
* Call your storage provider and save your new authResult object
_29
*/
_29
await identityVault.setValue('my-auth-result', JSON.stringify(newAuthResult));
_29
return true;
_29
} catch (e) {
_29
console.error(e);
_29
/**
_29
* Call your storage provider and remove your authResult object
_29
*/
_29
await identityVault.removeValue('my-auth-result');
_29
return false;
_29
}
_29
}

warning

This implementation assumes that each time you need your AuthResult you read it from your storage provider. If you cache this value in memory, your implementation should be updated to reflect that.

Migrating a user session from version 3 to 4

If you are okay with your users having to re-authenticate, you can skip this section. However, if you want to migrate your users to the new version of Auth Connect, you will need to migrate their old Auth Connect session data to the new format. This can be done by manually retrieving your existing session data from your storage provider and then refreshing the session with the new version of Auth Connect. This will result in a new AuthResult object that you can then save to your storage provider.

Previously, Auth Connect 3 would have stored session information under the following keys:

  • _ionicAuth.accessToken
  • _ionicAuth.refreshToken
  • _ionicAuth.idToken

_22
/**
_22
* This is just an example of how you might retrieve these values from your storage provider.
_22
* You will need to implement this yourself based on your storage provider.
_22
*/
_22
async function getLegacySessionFromStorageProvider() {
_22
const accessToken = await identityVault.getValue('_ionicAuth.accessToken');
_22
const refreshToken = await identityVault.getValue('_ionicAuth.refreshToken');
_22
const idToken = await identityVault.getValue('_ionicAuth.idToken');
_22
return { accessToken, refreshToken, idToken };
_22
}
_22
_22
async function migrateAuthConnectSession() {
_22
const provider = new Auth0Provider();
_22
const options: ProviderOptions = {...};
_22
const { accessToken, refreshToken, idToken } = await getLegacySessionFromStorageProvider();
_22
const tempAuthResult: AuthResult = await AuthConnect.buildAuthResult(provider, options, {
_22
accessToken,
_22
refreshToken,
_22
idToken,
_22
})
_22
const newAuthResult = await AuthConnect.refreshSession(provider, tempAuthResult);
_22
}

Need Help Upgrading?

If you need help upgrading your application to the new version of Auth Connect, please reach out to Ionic Enterprise Support with any questions you may have.