@chathura_dev/expo-msal
v0.1.15
Published
MSAL (Microsoft Authentication Library) integration for Expo applications
Maintainers
Readme
expo-msal
Modern Expo module for Microsoft Authentication Library (MSAL) built with the Expo Modules API. Works with Azure AD and Azure AD B2C on iOS and Android.
Features
- Native MSAL SDK integration (Swift/Kotlin)
- Interactive and silent token acquisition
- Multi-account support with account change events
- TypeScript-first API with generated types
- JSI bridge for performance
Documentation
Android MSAL Documentation
- Android MSAL Guide - Comprehensive Android MSAL setup and configuration
- Android Quick Reference - Quick code snippets and examples
- MSAL 6.x Migration - Migration guide from MSAL 5.x to 6.x
- Android Implementation Summary - Technical implementation details
Troubleshooting
- Scope Troubleshooting - Fix "scopes have been declined" and other scope errors
General Documentation
- Setup Guide - Initial setup instructions for both platforms
- Quick Reference - Common usage patterns and TypeScript examples
- Implementation Summary - Technical implementation overview
Example Files
- AndroidManifest.xml Template - Complete manifest configuration example
Install (fresh Expo app)
npm install expo-msal
# or
yarn add expo-msal
# prepare native projects (required once after install or when native config changes)
Azure AD setup
- In Azure Portal create an app registration and note
clientIdandtenantId(Directory ID). - Add redirect URIs:
- iOS:
msauth.<your.bundle.id>://auth - Android:
msauth://<your.package.name>/<YOUR_SIGNATURE_HASH>
- iOS:
- Add required scopes (e.g.,
User.Read) and expose any custom API scopes if needed.
App usage
import { PublicClientApplication, MSALConfiguration } from 'expo-msal';
const config: MSALConfiguration = {
auth: {
clientId: '<CLIENT_ID>',
authority: 'https://login.microsoftonline.com/<TENANT_ID>',
redirectUri: 'msauth.<your.bundle.id>://auth', // use Android URI on Android
},
};
const pca = new PublicClientApplication(config);
await pca.init();
const result = await pca.acquireToken({ scopes: ['User.Read'] });
console.log(result.accessToken);iOS setup (bare or prebuilt)
- Add URL schemes and queries to
ios/<app>/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>msauthv2</string>
<string>msauthv3</string>
</array>- Install pods:
cd ios && pod install && cd ..- Ensure the redirect URI in Azure matches
msauth.<your.bundle.id>://auth. - Build/run:
npx expo run:ios.
Android setup (bare or prebuilt)
Step 1: Add required permissions
In android/app/src/main/AndroidManifest.xml, add these permissions before the <application> tag:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>Step 2: Configure BrowserTabActivity
In android/app/src/main/AndroidManifest.xml, inside <application> add the BrowserTabActivity:
IMPORTANT: Do NOT URL encode the signature hash in AndroidManifest.xml (but DO encode it in Azure redirect URI and auth config)
<activity
android:name="com.microsoft.identity.client.BrowserTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="msauth"
android:host="YOUR_PACKAGE_NAME"
android:path="/YOUR_BASE64_ENCODED_SIGNATURE" />
</intent-filter>
</activity>Example:
<!-- For package: com.example.myapp -->
<!-- With signature hash: abc123XYZ== -->
<data
android:scheme="msauth"
android:host="com.example.myapp"
android:path="/abc123XYZ==" />Step 3: Add Maven repository
Add the Microsoft Device SDK feed to android/build.gradle (or settings.gradle under dependencyResolutionManagement):
allprojects {
repositories {
maven {
url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1'
}
}
}Step 4: Generate signature hash
For debug builds:
keytool -exportcert -alias androiddebugkey \
-keystore ~/.android/debug.keystore \
-storepass android -keypass android | \
openssl sha1 -binary | openssl base64For release builds:
keytool -exportcert -alias YOUR_RELEASE_KEY_ALIAS \
-keystore YOUR_RELEASE_KEY_PATH \
-storepass YOUR_STORE_PASSWORD -keypass YOUR_KEY_PASSWORD | \
openssl sha1 -binary | openssl base64Step 5: Configure redirect URI
In Azure Portal: Use URL-encoded format
msauth://YOUR_PACKAGE_NAME/YOUR_URL_ENCODED_SIGNATURE_HASHIn AndroidManifest.xml: Use plain base64 (NOT URL-encoded)
android:path="/YOUR_BASE64_SIGNATURE"In app config: Use URL-encoded format (same as Azure)
redirectUri: 'msauth://com.example.myapp/abc123XYZ%3D%3D'Step 6: Build and run
npx expo run:androidNote: The package name comes from context.getPackageName() which matches your build.gradle applicationId.
Common flows
- Acquire token interactively:
pca.acquireToken({ scopes: ['User.Read'] }) - Silent token:
pca.acquireTokenSilent({ scopes, account }) - List accounts:
pca.getAccounts() - Sign out:
pca.signOut({ account, signoutFromBrowser: true }) - Account change listener:
pca.addAccountChangeListener(cb)
Troubleshooting
Common Issues
- Redirect fails: verify bundle ID/package name + signature hash exactly match Azure redirect URI.
- Android missing
BrowserTabActivity: confirm manifest entry and rebuild afternpx expo prebuild. - iOS missing scheme: ensure
CFBundleURLTypesandLSApplicationQueriesSchemesare present, then reinstall pods. - Keystore changed: regenerate signature hash and update Azure + manifest.
- "Scopes have been declined": See Scope Troubleshooting Guide for detailed solutions:
- Verify permissions configured in Azure Portal
- Grant admin consent if required
- Check scope format (must be array of strings)
- Ensure scopes match your authority type (AAD vs B2C)
Requirements
- iOS 13+
- Android API 21+
- Expo SDK 51+
- React Native 0.70+
License
MIT if (accounts.length > 0) {
