Quickstart — React Native#
This walkthrough gets a HAAPI-authenticated login working in a fresh React Native app in roughly 20 minutes. It uses the SDK Layer — there is no UI Layer for React Native. Your host app renders the authentication screens using React components driven by the HaapiRepresentation discriminated union returned by the SDK.
Before You Start#
You’ll need:
- Node 22+, npm 10+, React Native 0.85.3+ and Expo SDK 56+.
- Xcode 26.2+ with iOS 16.4+ deployment target (for iOS builds).
- Android Studio with JDK 17+,
compileSdk36,minSdk26 (for Android builds). - A Curity Identity Server with a HAAPI-capable OAuth client configured. The
clientId, base URL, token endpoint, authorization endpoint, and redirect URI for that client. - A simulator / emulator or a physical device. Attestation requires a real device on both platforms; configure DCR fallback (Step 6) if you target simulators or untrusted devices.
See React Native Platform Notes for the full prerequisite matrix.
Step 1 — Install the Package#
npm install identityserver.haapi.reactnative.sdk
The native iOS and Android HAAPI SDKs are pulled in transitively — iOS via Swift Package Manager from https://github.com/curityio/ios-idsvr-haapi-sdk-dist, Android via Maven through Gradle. No separate native declarations are required.
For iOS, run pod install from your ios/ directory after the npm install (Expo autolinking ties the React Native module into the Pods graph). For Android, Gradle resolves the dependency on the next build.
Step 2 — Build the Configuration#
Configuration is composed in three layers: a top-level RNHaapiConfiguration that carries the server URLs and embeds platform-specific IOSConfiguration / AndroidConfiguration records.
import {
createHaapiConfiguration,
createIOSConfiguration,
createAndroidConfiguration,
noAuthentication,
} from 'identityserver.haapi.reactnative.sdk'
const iosConfig = createIOSConfiguration({
clientId: 'my-haapi-client',
appRedirect: 'haapi:start',
clientAuthenticationMethodConfiguration: noAuthentication(),
})
const androidConfig = createAndroidConfiguration({
clientId: 'my-haapi-client',
appRedirect: 'app://haapi',
clientAuthenticationMethodConfig: noAuthentication(),
})
const haapiConfig = createHaapiConfiguration({
baseUrl: 'https://idsvr.example.com',
tokenEndpointUrl: 'https://idsvr.example.com/oauth/v2/oauth-token',
authorizationEndpointUrl: 'https://idsvr.example.com/oauth/v2/oauth-authorize',
revocationEndpointUrl: 'https://idsvr.example.com/oauth/v2/oauth-revoke',
iosConfig,
androidConfig,
})
See Creating a HaapiAccessor for the full configuration surface and per-platform options.
Step 3 — Initialise the Accessor#
initializeForHaapi opens the native HAAPI accessor and returns a HaapiAccessor carrying both managers. The factory is async; await it before using either manager.
import { initializeForHaapi, getRNLogger, RNLogLevel } from 'identityserver.haapi.reactnative.sdk'
const logger = getRNLogger({ logLevel: RNLogLevel.Info, isSensitiveValueMasked: true })
const accessor = await initializeForHaapi(haapiConfig, logger)
// accessor.haapiManager and accessor.oauthTokenManager are now ready.
Strict re-init. initializeForHaapi (and initializeForOAuth) throw with error.code === HaapiErrorCode.AccessorAlreadyInitialized if an accessor is already held. Always call accessor.close() before re-initialising or switching modes.
Step 4 — Drive the HAAPI Flow#
Call start() to begin the flow. The returned HaapiResponse is a discriminated union — branch on responseCategory to handle representations vs server-side problems, then on representation.stepType to render the correct screen.
import { StepType } from 'identityserver.haapi.reactnative.sdk'
const response = await accessor.haapiManager.start()
if (response.responseCategory === 'representation') {
switch (response.representation.stepType) {
case StepType.InteractiveForm:
// Render your React form using response.representation.actions.
// Submit via accessor.haapiManager.submitForm(action, fieldValues).
break
case StepType.OAuthAuthorizationResponse:
// Flow complete — see Step 5 to exchange the code for tokens.
break
// …handle other step types: AuthenticatorSelector, Polling, Redirection, etc.
}
}
See React Native Representations for the full list of step types and the action / form-field shapes each one carries, and HAAPI Flow for the cross-platform stepping pattern.
Step 5 — Exchange the Code for Tokens#
When stepType === StepType.OAuthAuthorizationResponse, extract the authorization code from the step properties and exchange it for an access token through OAuthTokenManager.
import type { OAuthAuthorizationResponseStep } from 'identityserver.haapi.reactnative.sdk'
const step = response.representation as OAuthAuthorizationResponseStep
const code = step.properties.code
const tokens = await accessor.oauthTokenManager.fetchAccessToken(code)
if (tokens.responseType === 'success') {
// Persist tokens.refreshToken using a secure store (expo-secure-store, react-native-keychain, …).
// Use tokens.accessToken for authenticated requests until it expires.
} else {
// tokens.errorType / tokens.errorDescription describes an RFC 6749 OAuth error.
}
Step 6 — Cleanup (and Optional DCR Fallback)#
When you’re done with this accessor — typically at sign-out or before re-initialising for a different user — call close():
accessor.close()
If your target devices include simulators or untrusted devices where hardware-backed attestation isn’t available, configure DCR fallback in the platform config:
import { createIOSConfiguration, secretAuthentication } from 'identityserver.haapi.reactnative.sdk'
const iosConfig = createIOSConfiguration({
clientId: 'my-haapi-client',
appRedirect: 'haapi:start',
clientAuthenticationMethodConfiguration: secretAuthentication('dev-secret'),
dcrConfiguration: {
templateClientId: 'dcr-template-client-haapi-ios',
clientRegistrationEndpointUrl: 'https://idsvr.example.com/oauth/v2/oauth-registration',
},
})
The server must have a matching template client configured — see DCR for the server-side prerequisites.
Refresh-only Path#
If you already hold a persisted refresh token and only need to mint a new access token (no HAAPI flow, no attestation overhead), use initializeForOAuth instead:
import { initializeForOAuth } from 'identityserver.haapi.reactnative.sdk'
const accessor = await initializeForOAuth(haapiConfig, logger)
try {
const tokens = await accessor.oauthTokenManager.refreshAccessToken(persistedRefreshToken)
if (tokens.responseType === 'success') {
// Use tokens.accessToken.
}
} finally {
accessor.close()
}
Run It#
Build and run via Expo:
npx expo run:ios # iOS simulator or attached device
npx expo run:android # Android emulator or attached device
Tap your sign-in trigger; the SDK walks through the HAAPI flow, your host app renders each step, and oauthTokenManager.fetchAccessToken(code) delivers the access token.
Next: React Native SDK for the full topic list · React Native Representations for step-by-step rendering · Error Handling for the stable HaapiErrorCode enum