Authress authentication SDK for React Native. Implements the full OAuth 2.0 login flow with native mobile storage and deep link handling for iOS and Android.
npm install @authress/login-react-native react-native-encrypted-storage react-native-nitro-cookies react-native-quick-crypto1. Configure the deep link intent filter
In android/app/src/main/AndroidManifest.xml, add an intent filter to your main activity so Android routes the redirect URI back to your app:
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
...>
<!-- existing intent filters -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<!-- DEFAULT: required for the activity to receive implicit intents from outside the app -->
<category android:name="android.intent.category.DEFAULT" />
<!-- BROWSABLE: required so Chrome and Chrome Custom Tabs can trigger this intent -->
<category android:name="android.intent.category.BROWSABLE" />
<!-- Must match the redirectUri you pass to LoginClient -->
<data android:scheme="com.yourapp" android:host="auth" android:pathPrefix="/callback" />
</intent-filter>
</activity>2. Forward the deep link to React Native
In android/app/src/main/java/.../MainActivity.kt, if you aren't already processing intents, you need to accept the callback:
import android.content.Intent
import com.facebook.react.ReactActivity
class MainActivity : ReactActivity() {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
}
}1. Register the URL scheme
In ios/YourApp/Info.plist, add:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<!-- Must match the scheme in the redirectUri you pass to LoginClient -->
<string>com.yourapp</string>
</array>
</dict>
</array>2. Forward the deep link to React Native
In ios/YourApp/AppDelegate.swift:
import React
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ app: UIApplication, open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return RCTLinkingManager.application(app, open: url, options: options)
}
}Or in AppDelegate.mm (Objective-C):
#import <React/RCTLinkingManager.h>
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [RCTLinkingManager application:application openURL:url options:options];
}3. Install native pods
cd ios && pod installCreate a single LoginClient instance for your app — typically in a module you import wherever authentication is needed.
import { LoginClient } from '@authress/login-react-native';
export const loginClient = new LoginClient({
// Your Authress custom domain — https://authress.io/app/#/setup?focus=domain
authressApiUrl: 'https://login.yourdomain.com',
// Your application ID — https://authress.io/app/#/manage?focus=applications
applicationId: 'app_your-app-id',
// The deep link URI Authress redirects back to after login.
// Must match a registered redirect URI for the application.
redirectUri: 'com.yourapp://auth/callback',
});The constructor throws synchronously if any required setting is missing or invalid. It also automatically registers a deep link listener — when the user returns from the Authress login page, the SDK completes the authentication request without any extra wiring in your app.
Pass any console-compatible logger as the second argument to see debug output:
const loginClient = new LoginClient(settings, console);All methods return a Result from the neverthrow library. A Result is either Ok(value) or Err(error) — it never throws. Use .match(), .isOk(), .isErr(), or .unwrapOr() to handle both cases.
Call this on every route change to keep session state current. It uses a cached token when available; otherwise it calls the Authress server.
const isLoggedIn = await loginClient.userIsLoggedIn();
if (isLoggedIn) {
// session is valid — proceed to the app
} else {
// no active session — show the login screen
}Start the login request, open the browser, and the SDK takes care of the rest — it listens for the deep link redirect and completes the authentication automatically.
import { Linking } from 'react-native';
const result = await loginClient.authenticate({
// Optional: specify a connection directly, or let the user pick on the Authress-hosted login page
connectionId: 'google',
});
if (result.isOk()) {
// Open the Authress-hosted login page in the device browser
await Linking.openURL(result.value.authenticationUrl);
} else {
console.error('Failed to start login', result.error);
}When the user returns via the deep link, the SDK automatically calls completeAuthenticationRequest and resolves any pending waitForToken calls.
Use waitForToken when you need a bearer token and are willing to wait for a session to become active (e.g. on app startup while restoring a previous session).
const result = await loginClient.waitForToken({ timeoutInMillis: 5000 });
if (result.isOk()) {
// Token is available — retrieve it with getToken()
const tokenResult = await loginClient.getToken();
if (tokenResult.isOk()) {
const token = tokenResult.value;
// Use as: Authorization: Bearer <token>
}
} else {
// result.error.code === 'TokenTimeoutError'
// No token arrived within the timeout — redirect to login
}Use getToken() directly when you need the token string immediately with no waiting:
const tokenResult = await loginClient.getToken();
if (tokenResult.isOk()) {
const token = tokenResult.value;
}
// Returns Err(NotLoggedInError) immediately if there is no active sessionReturns decoded claims from the session token — useful for personalising the UI.
const result = await loginClient.getUserIdentity();
if (result.isOk()) {
console.log(result.value.userId); // e.g. 'user|00001'
// result.value also contains all other JWT claims
} else {
// result.error.code === 'NotLoggedInError'
}Fetches the user's profile from Authress, including all linked identities. Requires an active session.
const result = await loginClient.getUserProfile();
if (result.isOk()) {
for (const { connection } of result.value.linkedIdentities) {
console.log(connection.connectionId, connection.userId);
}
} else if (result.error.code === 'NotLoggedInError') {
// user is not logged in
} else {
// HTTP error
}Clears the local session and invalidates the server-side session.
await loginClient.logout();
// Result is always Ok — errors during server-side logout are swallowedAfter logout, getToken() returns Err, waitForToken() blocks again, and userIsLoggedIn() returns false.
Links a new identity provider to the currently logged-in user. Follows the same flow as authenticate — open authenticationUrl in the browser and the SDK handles the redirect automatically. Either connectionId or tenantLookupIdentifier is required.
const result = await loginClient.linkIdentity({ connectionId: 'github' });
if (result.isOk()) {
await Linking.openURL(result.value.authenticationUrl);
} else if (result.error.code === 'NotLoggedInError') {
// user must be logged in to link an identity
} else {
console.error('Link identity failed', result.error);
}// List registered MFA devices
const devicesResult = await loginClient.getDevices();
const devices = devicesResult.unwrapOr([]);
// Remove a device
const deleteResult = await loginClient.deleteDevice(deviceId);
if (deleteResult.isErr()) {
console.error('Failed to remove device', deleteResult.error);
}All errors are typed and carry a discriminating property. No method throws — use .isErr() to check for failure, then inspect the error.
Returned as Err values when a precondition is not met. Match on error.code:
| Class | error.code |
When |
|---|---|---|
NotLoggedInError |
'NotLoggedInError' |
Operation requires a logged-in session |
NoAuthenticationRequestInProgressError |
'NoAuthenticationRequestInProgressError' |
completeAuthenticationRequest called with no pending login |
AuthenticationRequestMismatchError |
'AuthenticationRequestMismatchError' |
authenticationRequestId in the redirect does not match the pending request |
TokenTimeoutError |
'TokenTimeoutError' |
waitForToken timeout elapsed before a session arrived |
InvalidConnectionError |
'InvalidConnectionError' |
linkIdentity called without connectionId or tenantLookupIdentifier |
SecurityContextError |
'SecurityContextError' |
Encrypted storage is unavailable (device security context error) |
Returned when a network request to the Authress service fails. All three types are part of the AuthressHttpError union. Match on error.name:
error.name |
When |
|---|---|
'AuthressHttpNetworkError' |
Request never reached the server (network offline, DNS failure). Retried up to 5 times before returning this error. |
'AuthressHttpClientError' |
Authress returned a 4xx response |
'AuthressHttpServiceError' |
Authress returned a 5xx response |
Each HTTP error includes url, method, and data. Client and service errors also include status and headers.
import type { AuthressHttpError } from '@authress/login-react-native';
const result = await loginClient.authenticate({ connectionId: 'google' });
if (result.isErr()) {
const error = result.error;
// Application errors — check error.code
if (error.code === 'SecurityContextError') {
// encrypted storage unavailable — device security context error
}
// HTTP errors — check error.name
else if (error.name === 'AuthressHttpNetworkError') {
// device is offline
} else if (error.name === 'AuthressHttpClientError') {
console.error(`Bad request: ${error.status}`, error.data);
} else if (error.name === 'AuthressHttpServiceError') {
console.error(`Authress service error: ${error.status}`);
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
authressApiUrl |
string |
Yes | Your Authress custom domain |
applicationId |
string |
Yes | Your Authress application ID |
redirectUri |
string |
Yes | Deep link URI registered for the application |
logger |
Logger |
No | Optional logger (console works) |
Throws synchronously on invalid settings.
Promise<boolean>
Checks if a valid session exists. Uses the cached token when available; otherwise calls the Authress API. Returns Ok(true) if the session is active, Ok(false) if not logged in or if the server call fails.
Call on every route change.
Promise<Result<AuthenticateResponse, AuthressHttpError | SecurityContextError>>
Starts the login flow. Returns authenticationUrl to open in the device browser. The SDK automatically handles the deep link redirect to complete the flow.
| Option | Type | Description |
|---|---|---|
connectionId |
string |
Log in directly with a specific provider connection |
tenantLookupIdentifier |
string |
Resolve the connection from a tenant identifier |
inviteId |
string |
Accept an invitation |
redirectUrl |
string |
Override the redirect URI from settings |
scopes |
string[] |
Additional scopes to request |
audiences |
string[] |
Additional audiences for the token |
connectionProperties |
Record<string, string> |
Provider-specific properties |
multiAccount |
boolean |
Enable multi-account login (default: false) |
Promise<Result<void, AuthFlowError | AuthressHttpError>>
Completes the login flow after the deep link redirect. Called automatically by the SDK when the deep link is received — you only need to call this directly if you are managing the deep link yourself.
Promise<Result<string, NotLoggedInError>>
Returns the current bearer token, or Err(NotLoggedInError) if there is no active session. Does not wait or make network calls.
Promise<Result<void, TokenTimeoutError>>
Blocks until a session token is available or the timeout elapses. Use getToken() after this resolves to retrieve the token string.
| Option | Type | Default | Description |
|---|---|---|---|
timeoutInMillis |
number |
5000 |
Timeout in ms. 0 = fail immediately. -1 = wait indefinitely. |
Promise<Result<void, never>>
Clears the local session and calls the Authress logout endpoint. Always resolves Ok — server-side errors are swallowed.
Promise<Result<UserIdentity, NotLoggedInError>>
Returns decoded claims from the session token. identity.userId is the user's unique identifier. The identity object also contains all other JWT claims.
Promise<Result<UserProfile, AuthressHttpError | NotLoggedInError>>
Fetches the user's full profile from Authress, including all linked identities (profile.linkedIdentities).
Promise<Result<AuthenticateResponse, AuthressHttpError | SecurityContextError | NotLoggedInError | InvalidConnectionError>>
Links a new identity provider to the current user. Returns authenticationUrl to open in the device browser. Either connectionId or tenantLookupIdentifier is required.
Promise<Result<Device[], AuthressHttpError | NotLoggedInError>>
Returns the list of MFA devices registered for the current user. Returns Ok([]) if not logged in or no devices are registered.
Promise<Result<void, AuthressHttpError | NotLoggedInError>>
Removes the MFA device with the given deviceId.
