Skip to content

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

Open
Francesco-Voto wants to merge 1 commit into
mainfrom
feat/resume-android-flow
Open

Francesco-Voto wants to merge 1 commit 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

⚠️ No Changeset found

Latest commit: aa8db36

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a 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 23, 2026 9:55am 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 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),

This branch was successfully deployed

1 active deployment
Preview — aa8db365 Deployed Sep 23, 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.

2 participants