Skip to content

feat: allow to resume the request if androdi OS kills the process - #1146

Merged
zibs merged 5 commits into
mainfrom
feat/resume-android-flow
Sep 30, 2026
Merged

zibs merged 5 commits into
mainfrom
feat/resume-android-flow

Conversation

@Francesco-Voto

Copy link
Copy Markdown
Collaborator

Description

On Android, the OS can kill the app process while the user is away in the Custom Tab completing
login (e.g. under memory pressure). When the app restarts, React Native drops the resulting
activity result because it arrives before the JS context is ready
(react/react-native#30277), so the in-flight authorize() promise is lost and the user's
login silently fails to complete even though the browser already returned a valid response.

This adds a resumePendingAuthorize() API to recover from that case:

  • RNAppAuthModule now stashes the raw activity result in a static field
    (stashAuthorizationResult) when it's received with no in-flight authorize() promise on the
    module instance, instead of discarding it.
  • The new resumePendingAuthorize native method and JS/TS export claim that stashed result,
    re-derive the token request from the AuthorizationResponse (which carries the PKCE code
    verifier), and complete the token exchange.
  • Consumers must forward MainActivity.onActivityResult to
    RNAppAuthModule.stashAuthorizationResult and call resumePendingAuthorize() on startup;
    it resolves null (safe to call unconditionally) when there's nothing to resume, and always
    resolves null on iOS.
  • Also moves AuthorizationService construction and createCustomTabsIntentBuilder() off the
    main thread in authorize(), since both are @WorkerThread calls that could block the UI for
    up to a second.
  • Documented the new API and the required MainActivity wiring in
    docs/docs/usage/authorization.md.

Steps to verify

  1. Wire up MainActivity.onActivityResult to call RNAppAuthModule.stashAuthorizationResult
    as shown in the updated docs, and call resumePendingAuthorize() on app startup.
  2. Run authorize() against a test IdP, and while the Custom Tab is open, kill the app process
    from Android Studio's Logcat ("Terminate Application") or via
    adb shell am kill <package>.
  3. Complete the login in the browser; the app should cold-start, and resumePendingAuthorize()
    should resolve with a valid token response instead of the flow silently failing.
  4. Confirm a normal (non-killed) authorize() flow still resolves as before, and that
    resumePendingAuthorize() resolves null when called with nothing pending.
  5. Confirm resumePendingAuthorize() resolves null immediately on iOS.

@changeset-bot

changeset-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18b6780

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
react-native-app-auth Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
react-native-app-auth Ready Ready Preview Sep 30, 2026 8:32pm UTC

Request Review


private static final AtomicReference<Intent> sStashedAuthorizationResult = new AtomicReference<>();

public static void stashAuthorizationResult(Intent data) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static void stashAuthorizationResult(Intent data) {
public static void stashAuthorizationResult(final Intent data) {


authService.performTokenRequest(tokenRequest, new AuthorizationService.TokenResponseCallback() {
@Override
public void onTokenRequestCompleted(TokenResponse resp, AuthorizationException ex) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public void onTokenRequestCompleted(TokenResponse resp, AuthorizationException ex) {
public void onTokenRequestCompleted(final TokenResponse resp, final AuthorizationException ex) {

Comment thread packages/react-native-app-auth/index.js Outdated
Comment on lines +282 to +293
} = {}) => {
if (Platform.OS !== 'android') {
return Promise.resolve(null);
}

validateHeaders(customHeaders);
validateConnectionTimeoutSeconds(connectionTimeoutSeconds);

return wrapNativeAuthPromise(
RNAppAuth.resumePendingAuthorize(
additionalParameters,
convertTimeoutForPlatform(Platform.OS, connectionTimeoutSeconds),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} = {}) => {
if (Platform.OS !== 'android') {
return Promise.resolve(null);
}
validateHeaders(customHeaders);
validateConnectionTimeoutSeconds(connectionTimeoutSeconds);
return wrapNativeAuthPromise(
RNAppAuth.resumePendingAuthorize(
additionalParameters,
convertTimeoutForPlatform(Platform.OS, connectionTimeoutSeconds),
} = {}) => {
const platform = Platform.OS
if (platform !== 'android') {
return Promise.resolve(null);
}
validateHeaders(customHeaders);
validateConnectionTimeoutSeconds(connectionTimeoutSeconds);
return wrapNativeAuthPromise(
RNAppAuth.resumePendingAuthorize(
additionalParameters,
convertTimeoutForPlatform(platform, connectionTimeoutSeconds),

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Resumed flows currently break client-authenticated and skipped-exchange configurations, and the background launch retains a stale Activity reference.

Review effort: Balanced
Findings: 3 Medium severity · 2 Low severity

Open (5)
What changed in this PR

Adds Android authorization recovery after process termination and moves Custom Tab setup off the UI thread.

Changes:

  • Adds resumePendingAuthorize() to JavaScript, TypeScript, and Android.
  • Stashes authorization results until React Native initializes.
  • Documents required Android activity forwarding.
File Description
index.js Exposes the resume API.
index.d.ts Defines resume API types.
RNAppAuthModule.java Implements result recovery and background Custom Tab setup.
authorization.md Documents setup and usage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/docs/usage/authorization.md
Comment on lines +277 to +282
export const resumePendingAuthorize = ({
additionalParameters,
dangerouslyAllowInsecureHttpRequests = false,
customHeaders,
connectionTimeoutSeconds,
} = {}) => {
Match the existing wrapper test mocks and address the platform lookup review suggestion.
@zibs
zibs merged commit 5b971ef into main Sep 30, 2026
3 checks passed
@zibs
zibs deleted the feat/resume-android-flow branch September 30, 2026 20:34
@github-actions github-actions Bot mentioned this pull request Sep 30, 2026

This branch was successfully deployed

1 active deployment
Preview — 18b6780c Deployed Sep 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants