Skip to main content

Expo

Expo users get almost the whole integration applied for them. Add the config plugin, run expo prebuild, and read the warnings it prints.

app.json
{
"expo": {
"plugins": [
["react-native-intune", { "androidSignatureHash": "Xo8W…yr9iU=" }]
]
}
}

Two kinds of configuration, and they are not interchangeable

This is the thing to get straight before anything else, because putting a value in the wrong place fails in a way that does not name the place.

Where it goesWhy
Build-timePlugin props in app.jsonIt has to be written into a native file — a plist key, an entitlement, a manifest activity. There is no runtime equivalent.
Runtimeconfigure() in your codeIt identifies a tenant. One build serves many customers, so these cannot be baked in.

Everything that identifies who you are talking to — clientId, tenantId, authority, redirectUri — is runtime, and comes from your own backend:

app/startup.ts
await Intune.configure({
clientId: cfg.aadClientId,
tenantId: cfg.aadTenantId,
authority: cfg.aadAuthority,
redirectUri: cfg.aadRedirectUri,
});
Do not put ADALClientId, ADALAuthority or ADALRedirectUri in the plist

The plugin deletes them if it finds them. A plist key alongside a runtime override is a known cause of enrollment failing with an authorization error, and configure() refuses to start when it sees one — so a prebuild that reintroduces them produces an app that cannot run.

Plugin props

Three, and only one of them cannot be omitted.

androidSignatureHash — required for sign-in on Android

The base64 SHA-1 of the certificate your app is signed with. It goes into the MSAL redirect activity, and it cannot be derived: an EAS build is signed with a keystore Expo manages, so only the project owner can read it.

eas credentials

The same value goes in your Entra app registration's redirect URI, where it is percent-encoded:

msauth://com.yourcompany.yourapp/Xo8W%2Fyr9iU%3D

The plugin writes the decoded form into the manifest. Same value, two spellings, in two places that must agree.

Without it, the redirect activity is skipped

The plugin warns and writes nothing rather than guessing a hash. A wrong hash fails at the first sign-in with an error that names neither key, which is a considerably worse afternoon than a warning during prebuild.

maxFileProtectionLevel — if your app reads its own files while locked

The SDK's default, NSFileProtectionComplete, makes protected files unreadable roughly ten seconds after the device locks — enough to break a local database, a background sync, or anything on a timer.

["react-native-intune", { "maxFileProtectionLevel": "completeUntilFirstUserAuthentication" }]

Accepted values are the FileProtectionLevel members: complete, completeUnlessOpen, completeUntilFirstUserAuthentication, none.

keychainGroup — only if your app already has its own MSAL cache group

Defaults to com.microsoft.adalcache, which is what you want unless the app already uses something else. Set it and the plugin puts it in the entitlements and writes ADALCacheKeychainGroupOverride to match, because those two must never disagree.

["react-native-intune", { "keychainGroup": "com.yourcompany.shared.cache" }]

Pass the same value to configure({ keychainGroupOverride }).

Why this needs a prop at all

ADALCacheKeychainGroupOverride is plist-only — the SDK reads it at launch and there is no setter. configure() rejects keychainGroupOverride when the plist disagrees, rather than accepting a value it cannot apply. Since prebuild regenerates the plist, without this prop an Expo app could not use a custom group at all: it would fail with E_PLIST_CONFLICT and there would be nowhere to fix it.

What the plugin does

FileChange
EntitlementsKeychain sharing groups, in the required order, preserving any you already had
Info.plistThe msauth.… URL type, broker query schemes, removal of the three ADAL* identity keys, and the two plist-only settings above
AndroidManifest.xmlBroker <queries>, and the MSAL BrowserTabActivity
android/app/build.gradleThe MAM Gradle plugin, applied to your app module
android/build.gradleThe plugin jar and javassist on the buildscript classpath
MainApplication.kt / .javaSuperclass changed to MAMApplication, and the auth callback registered

Why this is automatic here and manual everywhere else

npx react-native-intune setup deliberately refuses to run on install, because the files it edits live in your git repository — a script that rewrites them fights your own changes and re-applies itself on every version bump.

A config plugin has neither problem. It runs during expo prebuild, against the android/ and ios/ directories prebuild has just generated. There is nothing of yours to overwrite and nothing to re-apply later.

That difference is why Expo users get the MAMApplication change automatically, while in a bare project doctor can only tell you to make it yourself.

What the plugin cannot do

The IntuneMAMConfigurator build phase. It is Microsoft's tool, it operates on your generated Xcode project, and it must be re-run whenever the plist, entitlements or SDK version change. Add it as a build phase yourself — see iOS setup.

Kotlin DSL build files. If your project uses build.gradle.kts, the plugin warns and leaves it alone rather than editing a file it cannot parse reliably.

Verifying it worked

expo prebuild prints a warning for anything it skipped. Read them, then:

npx react-native-intune doctor

It inspects the generated projects the same way it inspects a bare one.

If prebuild warned that MainApplication could not be modified, stop

That is one of the omissions that builds successfully, runs, and leaves the app unprotected while everyone believes protection is in place. See Traps.