Auth Connect Fundamentals
Overview
Auth Connect allows developers to easily connect their Capacitor applications to a backend authentication provider using the standardized OAuth 2.0 protocol as defined in RFC6749. This document will walk you through the basics of how to use the Auth Connect plugin in your application.
Initial Configuration
Ensure that you're configured your Custom URL Scheme in the installation instructions, otherwise the OAuth flow will not work.
Auth Connect provides several configuration options that you should set before calling any other methods. These options define the behavior of the plugin in your application and let you customize the experience within the scope of the framework for your users. You set these options by calling the setup()
method on the plugin. The various parameters are described in the AuthConnectConfig Reference Docs.
_15import { AuthConnect } from '@ionic-enterprise/auth';_15_15await AuthConnect.setup({_15 /**_15 * Log level is used to control the amount of logging that is output to the console._15 * Typically, in production you'd set this to 'ERROR', but in development_15 * you may want to set it to 'DEBUG' to see more information._15 */_15 logLevel: 'DEBUG',_15 /**_15 * Platform communicates with Auth Connect which platform you are using._15 * This is likely to be dynamically set at runtime if you support multiple platforms._15 */_15 platform: 'capacitor'_15});
Working with the Auth Connect API
The simplest use with Auth Connect involves calling the login()
method to authenticate a user and then calling the logout()
method to log them out.
Login
When logging in a user, you need to pass two different objects. Your provider class, as well as the provider options. These two objects contain the information that Auth Connect needs to communuicate with your Auth Provider. This example uses the Auth0Provider
but you should use the class for your provider, or create your own custom provider.
_21import { AuthConnect, Auth0Provider, ProviderOptions } from '@ionic-enterprise/auth';_21_21const provider = new Auth0Provider();_21_21/**_21 * Most of these values are provided by your Auth Provider._21 */_21const providerOptions: ProviderOptions = {_21 clientId: 'my-special-id',_21 audience: '',_21 scope: 'openid profile email',_21 discoveryUrl: 'https://example.com/.well-known/openid-configuration',_21 /**_21 * The redirectUri and logoutUrl are the URLs that your provider will redirect_21 * to upon successful login and logout. These URLs must be registered with your_21 * provider and must match the URL that you are using in your app, including _21 * the custom URL scheme._21 */_21 redirectUri: 'mycustomscheme://login',_21 logoutUrl: 'mycustomscheme://logout',_21};
Once you have your provider and provider options, you can call the login()
method to authenticate a user. This method returns an AuthResult
on success that contains the user's auth tokens, such as access token or refresh token. If the user cancels the login flow or something goes wrong, the method will throw an error.
_10async function login() {_10 try {_10 const authResult = await AuthConnect.login(provider, providerOptions);_10 } catch (error) {_10 console.error(error);_10 }_10}
You should store this AuthResult
object, which we'll cover later.
Logout
To log a user out, you call the logout()
method, passing your provider information along with your AuthResult
. This method will return a Promise
that resolves when the logout is complete. If something goes wrong, the method will throw an error.
_10async function logout() {_10 try {_10 await AuthConnect.logout(provider, authResult);_10 } catch (error) {_10 console.error(error);_10 }_10}
Even if you destroy or lose your AuthResult
, that does not mean the user is logged out. Your authentication provider typically stores cookies in the webview that can automatically log in the user if you were to call login
again. You should always call logout
to ensure that the user is logged out.
Refreshing Tokens
Once you have an AuthResult
, you may want to refresh the session if your access token expires and you have a valid refresh token. This is done simply by passing your provider information along with the AuthResult
to the refreshSession()
method. This method will return a new AuthResult
on success. If the user cancels the login flow or something goes wrong, the method will throw an error.
_10async function refreshSession() {_10 try {_10 const updatedAuthResult = await AuthConnect.refreshSession(provider, authResult);_10 } catch (error) {_10 console.error(error);_10 }_10}
Make sure you use the updated AuthResult
after you refresh a session. The old AuthResult
will no longer be valid with your provider.
Checking the Authentication State
Checking if the user is authenticated is a complex topic that we cover fully in the Implementing isAuthenticated guide. You should determine within your organization what it means to be authenticated. For this simple example, let's assume that the user is authenticated if they have an access token that is not expired.
_10async function isAuthenticated(authResult: AuthResult) {_10 return (await AuthConnect.isAccessTokenAvailable(authResult)) && (await AuthConnect.isAccessTokenExpired(authResult) === false);_10}
Storing the Auth Result
You'll have noticed that the AuthResult
plays an important role with Auth Connect. It contains all the information about your current authentication session for the user. It's important that you store this object in a secure location that you can access later. We highly recommend using Identity Vault to securely store this information using the biometric security on device. However, the AuthResult
object is fully serializable, so you can store it using any storage mechanism you prefer.
On the web, typically you would store this information using localStorage
. On device, we highly discourage relying on localStorage
as there are circumstances where the Operating System can purge this data to free up space for the device. This result contains sensitive information, so always store it using the most secure mechanism available.
The simplest way to store and later use your AuthResult
is to simply create a mechanism to retrieve it. This can allow you to cache the result for quicker access while the app is running, but keep the data secured when the app is closed. The example below uses as simple closure with IdentityVault
to secure the AuthResult
as well as maintain a cache for quick reference.
_28import { AuthResult } from '@ionic-enterprise/auth';_28import { vaultInstance } from './my-vault';_28_28async function createAuthResultStorage() {_28 const authResultCache: AuthResult | null = null;_28_28 return {_28 async get() {_28 if (authResultCache) {_28 return authResultCache;_28 }_28_28 const authResult = await vaultInstance.getValue('authResult');_28 authResultCache = authResult;_28 return authResult;_28 },_28 async set(authResult: AuthResult) {_28 authResultCache = authResult;_28 await vaultInstance.setValue('authResult', authResult);_28 },_28 async clear() {_28 authResultCache = null;_28 await vaultInstance.removeValue('authResult');_28 }_28 };_28}_28_28export const authResultStorage = createAuthResultStorage();
This can then be used anytime you interact with Auth Connect
_18async function login() {_18 try {_18 const authResult = await AuthConnect.login(provider, providerOptions);_18 await authResultStorage.set(authResult);_18 } catch (error) {_18 console.error(error);_18 }_18}_18_18async function refreshSession() {_18 try {_18 const authResult = await authResultStorage.get();_18 const updatedAuthResult = await AuthConnect.refreshSession(provider, authResult);_18 await authResultStorage.set(updatedAuthResult);_18 } catch (error) {_18 console.error(error);_18 }_18}
Restoring an Authentication Session
Restoring a session when the application starts is a simple task given everything we know at this point. We need to ensure that we've called setup()
first, then we can retrieve our AuthResult
from storage. If we have a valid result object, we can then check if the result is valid, and if so we have a valid session.
_10async function restoreSession() {_10 await AuthConnect.setup({...});_10_10 const authResult = await authResultStorage.get();_10 if (authResult) {_10 return await isAuthenticated(authResult);_10 }_10_10 return false;_10}