Hawcx React Native SDK (V6)
Integrate Hawcx V6 in React Native with an adaptive authentication flow, redirects, backend exchange, and trusted-device support.
Overview
Hawcx V6 for React Native gives you a prompt-driven authentication flow that adapts to the authentication methods configured for your project. Your app starts a flow, renders the next prompt Hawcx returns, and completes sign-in by exchanging the resulting authorization code on your backend.
This is the recommended React Native integration path for new projects using Hawcx V6.
V6 docs, current React API names
The React Native package already exposes HawcxV6* types and helpers such as
useHawcxV6Auth, startV6Flow, and hawcxV6Client. Under the hood, the bridge
delegates to the production Hawcx iOS and Android SDKs.
Already using the existing React Native SDK flow?
If your app is already integrated with the existing V5 surface such as
useHawcxAuth, authenticate, and submitOtp, continue using the
V5 React Native guide. This page is
for the new V6 integration path only.
Which Guide Should You Use?
Use this V6 guide if:
- you are starting a new React Native integration
- you want an adaptive flow with backend-selected primary, MFA, redirect, and trusted-device steps
- you want to use the current
HawcxV6*React API surface
Use the V5 React Native guide if:
- your app already ships the existing V5 integration
- you still depend on
authenticate,submitOtp,useHawcxAuth, or older auth events - you are maintaining an existing production integration and are not ready to migrate yet
Incremental migration is supported
The React Native package still includes the older V5 helpers and bridge surface, so you can adopt the V6 flow in new screens while keeping existing V5 flows in place during migration.
Before You Begin
Before integrating the React Native SDK, make sure your Hawcx project is configured in the Hawcx dashboard:
- create or select your project
- configure the primary authentication step
- configure MFA and trusted-device behavior if needed
- generate a Config ID for the SDK
For product configuration details, see:
How the V6 Flow Works
- Your app initializes the React Native package with your Config ID and tenant host.
- You start the flow with a
flowType, usuallysignin, plus the user's identifier. - The native SDK returns the next prompt for that user and project configuration.
- Your React UI renders the current step:
- choose a method
- enter a verification code
- set up SMS
- set up TOTP
- continue a redirect
- wait for approval
- When the flow completes, the SDK returns
authCodeand, when applicable,codeVerifier. - Your backend exchanges the code and creates the user session.
Integration Responsibilities
Your app is responsible for:
- collecting the user's identifier
- rendering the current prompt
- sending the user's input back to the SDK
- handling redirects when prompted
- sending the final authorization code to your backend
The SDK handles:
- native protocol requests and required headers
- PKCE generation when needed
- trusted-device storage and secure device credentials
- device-trust processing
- approval polling when the flow requires it
Your backend handles:
- exchanging the authorization code
- verifying returned claims
- creating the app session
- returning the result your app needs to continue
What the SDK handles automatically
The React Native package keeps the JavaScript surface small while the native iOS and Android SDKs manage the protocol details for you, including PKCE when needed, secure trusted-device storage, and device-trust processing.
Requirements
- React Native 0.73+
- iOS 17.5+ for the bundled Hawcx iOS framework
- Android API 26+
- A Hawcx Config ID for your project
- Your Hawcx tenant base URL
Example base URL:
https://stage-api.hawcx.comFor the recommended V6 path, pass the tenant host root only. The native SDKs derive the
correct V5 and V6 routes from that host. Do not append /v1, /auth, or /hc_auth
yourself.
Install
1. Add the package
npm install @hawcx/[email protected]Pin to the latest released version your team has approved for production. Version
1.1.5 is the current React Native V6 release documented on this page.
2. Install iOS dependencies
cd ios
pod install
cd ..The package vendors HawcxFramework.xcframework through its Podspec, so no manual iOS
framework setup is required.
3. Configure Android Maven resolution
The React Native package depends on the released Hawcx Android SDK, so your Android app must be able to resolve the Hawcx Maven repo.
Add the Hawcx Maven repository:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/hawcx/hawcx_android_sdk/main/maven")
metadataSources {
mavenPom()
artifact()
}
}
}
}If your project still declares flatDir { dirs("libs") } or bundles a local
hawcx-*.aar, remove that and let Gradle resolve the native SDK from Maven.
Public Android Maven repo
The hosted Hawcx Maven repository is public. You do not need a GitHub token for the standard React Native setup shown here.
4. Rebuild the app
npm run ios
# or
npm run androidAndroid note
If your Android environment caches an older dependency graph, run cd android && ./gradlew clean
once before rebuilding.
Initialize the SDK
import { initialize } from '@hawcx/react-native-sdk';
await initialize({
projectApiKey: '<YOUR_CONFIG_ID>',
baseUrl: 'https://stage-api.hawcx.com',
autoPollApprovals: true,
});Initialization Notes
projectApiKeyis the Hawcx value provisioned for this integration. In current public releases, this is the same value you may receive as your project API key / Config ID.baseUrlshould point to your Hawcx tenant host root. Let the native SDKs derive the V5 and V6 routes from that host.autoPollApprovalsdefaults totrue, which is the right choice for most apps.relyingPartyis optional. Set it only when your backend expects theX-Relying-Partyheader for this integration.oauthConfigis not required for the recommended V6 flow. Keep OAuth client credentials on your backend.endpoints.authBaseUrlremains available only for backward compatibility and should be treated as deprecated in new integrations.
Build an Auth Screen
The recommended integration shape for React Native is a screen or coordinator that:
- holds the current
HawcxV6AuthState - starts the flow
- reacts to the current prompt
- forwards the user's input back to the SDK
import { useState } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import {
useHawcxV6Auth,
type HawcxV6Method,
} from '@hawcx/react-native-sdk';
export function V6AuthScreen() {
const [identifier, setIdentifier] = useState('');
const [code, setCode] = useState('');
const [phone, setPhone] = useState('');
const [totp, setTotp] = useState('');
const v6 = useHawcxV6Auth(undefined, { flowType: 'signin' });
const start = async () => {
await v6.start({
flowType: 'signin',
identifier: identifier.trim(),
});
};
const renderPrompt = () => {
switch (v6.state.status) {
case 'select_method':
return v6.state.prompt?.prompt.type === 'select_method'
? v6.state.prompt.prompt.methods.map((method: HawcxV6Method) => (
<Button
key={method.id}
title={method.label}
onPress={() => void v6.selectMethod(method.id)}
/>
))
: null;
case 'enter_code':
return (
<>
<TextInput value={code} onChangeText={setCode} keyboardType="number-pad" />
<Button title="Continue" onPress={() => void v6.submitCode(code)} />
</>
);
case 'setup_sms':
return (
<>
<TextInput value={phone} onChangeText={setPhone} keyboardType="phone-pad" />
<Button title="Continue" onPress={() => void v6.submitPhone(phone)} />
</>
);
case 'setup_totp':
return (
<>
<Text>Scan the authenticator QR code, then enter a fresh code.</Text>
<TextInput value={totp} onChangeText={setTotp} />
<Button title="Continue" onPress={() => void v6.submitTotp(totp)} />
</>
);
case 'enter_totp':
return (
<>
<TextInput value={totp} onChangeText={setTotp} />
<Button title="Continue" onPress={() => void v6.submitTotp(totp)} />
</>
);
case 'await_approval':
return <Text>Waiting for approval...</Text>;
case 'redirect':
return <Text>Continue in the browser to finish this step.</Text>;
default:
return null;
}
};
return (
<View>
<TextInput value={identifier} onChangeText={setIdentifier} />
<Button title="Continue" onPress={() => void start()} />
{renderPrompt()}
</View>
);
}Starting Authentication
flowType supports:
signinsignupaccount_manage
Most apps should start with signin:
await v6.start({
flowType: 'signin',
identifier: '[email protected]',
});Additional fields are available when your tenant policy requires them:
await v6.start({
flowType: 'signin',
identifier: '[email protected]',
startToken: '<optional-start-token>',
inviteCode: '12345678',
});startToken is optional and is only needed when your backend or hosted flow gives your
app a pre-issued token to resume or continue a specific start path.
You can also pass codeChallenge, but in most cases you do not need to. If you omit it,
the native SDK generates PKCE automatically and returns codeVerifier in the completed
event.
Flow State and Prompt Types
useHawcxV6Auth() exposes a normalized React state machine.
Possible state.status values:
identifierloadingselect_methodenter_codesetup_smssetup_totpenter_totpredirectawait_approvalcompletederror
Helpful state fields:
state.step- label the current stage such as Primary, MFA, or Device Trust
state.risk- show a step-up or risk warning when the backend flags the session
state.traceId- capture this in logs or support tickets when it is returned
state.resend- contains resend availability and countdown metadata
state.isLoading,state.requiresRedirect, andstate.awaitingApproval- use these convenience flags for button states and UI transitions
Resend, Polling, and Flow Control
useHawcxV6Auth() exposes:
resend()poll()cancel()changeIdentifier()reset()canResendresendAvailabilitysecondsUntilResend
For email OTP and SMS OTP steps, use the resend helpers:
if (v6.canResend) {
await v6.resend();
}When the current prompt is await_approval, polling is handled automatically when
autoPollApprovals is enabled. You can still call poll() manually if your product
needs explicit refresh controls.
Use changeIdentifier() when the user wants to go back and enter a different email or
phone number without remounting the whole screen.
Imperative Client and Low-Level Events
If you prefer an imperative integration instead of a React hook, use hawcxV6Client:
import {
addV6FlowListener,
hawcxV6Client,
} from '@hawcx/react-native-sdk';
const subscription = addV6FlowListener((event) => {
console.log(event.type, event.payload);
});
await hawcxV6Client.start({
flowType: 'signin',
identifier: '[email protected]',
});
subscription.remove();This is useful in Redux sagas, state machines, or non-React coordinators.
Handle Redirect Steps
When the current prompt is redirect, open the URL in the browser and forward the return
URL back into the SDK.
import { useEffect } from 'react';
import { Linking } from 'react-native';
useEffect(() => {
const subscription = Linking.addEventListener('url', ({ url }) => {
void v6.handleRedirectUrl(url);
});
return () => subscription.remove();
}, [v6.handleRedirectUrl]);
const openRedirect = async () => {
if (v6.state.prompt?.prompt.type !== 'redirect') {
return;
}
await Linking.openURL(v6.state.prompt.prompt.url);
};React Native handles the JavaScript side of the callback, but you still need to register your callback scheme natively on iOS and Android so the app receives the return URL.
Platform-specific references:
Handle Completion and Backend Exchange
When the flow completes, the SDK returns:
sessionauthCodeexpiresAtcodeVerifierwhen PKCE was generated by the SDKtraceIdfor correlation and support logs, when returned
Use authCode and codeVerifier as the primary inputs for the backend exchange.
expiresAt, session, and traceId are useful for telemetry, timing, and support
tooling, but they are not the core exchange inputs. Treat traceId as optional; some
successful flows can complete without one.
Include codeVerifier whenever the SDK returns it. If your app supplied a custom
codeChallenge, send the matching verifier from that flow to your backend as part of the
exchange.
Send the completion payload to your backend immediately over HTTPS. Do not perform the code exchange from the React Native app.
Recommended payload shape:
{
"authCode": "<authCode>",
"codeVerifier": "<optional-codeVerifier>",
"identifier": "[email protected]",
"session": "<optional-session>"
}Your backend should:
- exchange
authCodeandcodeVerifierwith the Hawcx backend SDK - verify the returned claims
- create your app session or tokens
- return the app auth result your React Native app needs
React Native app-to-backend example
import { useEffect } from 'react';
import {
storeBackendOAuthTokens,
useHawcxV6Auth,
} from '@hawcx/react-native-sdk';
useEffect(() => {
if (v6.state.status !== 'completed' || !v6.state.completed) {
return;
}
const run = async () => {
const response = await fetch('https://your-backend.example.com/api/hawcx/exchange', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
authCode: v6.state.completed.authCode,
codeVerifier: v6.state.completed.codeVerifier,
identifier,
session: v6.state.completed.session,
}),
});
if (!response.ok) {
throw new Error('Backend exchange failed');
}
const result = await response.json();
if (result.accessToken) {
await storeBackendOAuthTokens(
identifier,
result.accessToken,
result.refreshToken,
);
}
};
void run();
}, [identifier, v6.state]);This example shows the app-to-backend handoff only. Your backend then uses the Hawcx backend SDK to exchange and verify the code before it creates the user session.
Backend implementation guides:
QR Approvals and Web Login Helpers
The React Native package also exposes helpers for QR approval and legacy web-login scans:
routeWebLoginScan(raw)approveV6Qr(rawPayload, identifier, options)useHawcxWebLogin()
Use routeWebLoginScan(raw) to decide whether a scanned payload is:
- a protocol QR payload (
protocol_qr) - a legacy PIN flow (
legacy_pin) - invalid input (
invalid)
For protocol QR payloads, you can approve directly from React Native:
import { approveV6Qr, routeWebLoginScan } from '@hawcx/react-native-sdk';
const route = routeWebLoginScan(scanValue);
if (route.kind === 'protocol_qr') {
const result = await approveV6Qr(route.payload.raw, identifier, {
rememberDevice: true,
});
console.log(result.outcome, result.payloadType);
}Existing V5 and Shared Helpers
The package still includes the older React Native auth surface for apps that already use it, including:
authenticate,submitOtp,useHawcxAuthuseHawcxWebLoginsetPushDeviceTokennotifyUserAuthenticatedhandlePushNotification,approvePushRequest,declinePushRequest
Shared helpers such as initialize and storeBackendOAuthTokens remain available across
the current package surface.
That makes incremental migration possible: new V6 flows can live on useHawcxV6Auth
while existing utilities remain available in the same package.