Skip to content

Dispatch customOAuthState before signInWithRedirect_failure on OAuth error redirects #14853

Description

@y-hsgw

Is this related to a new or existing framework?

Next.js

Is this related to a new or existing API?

Authentication

Is this related to another service?

Amazon Cognito (Hosted UI / OAuth)

Describe the feature you'd like to request

When signInWithRedirect fails during the OAuth callback (e.g. Cognito redirects back with ?error=...&error_description=...&state=..., such as when a PreSignUp Lambda trigger throws to block the sign-in), the customOAuthState Hub event is never dispatched — only signInWithRedirect_failure fires.

This means any customState passed to signInWithRedirect({ customState: ... }) is lost on failure, even though the state query parameter (which encodes the custom state) is still present in the callback URL in the error case.

In completeOAuthFlow.ts:

const error = urlParams.searchParams.get('error');
const errorMessage = urlParams.searchParams.get('error_description');

if (error) {
  throw createOAuthError(errorMessage ?? error);
}

The function throws immediately and never reaches completeFlow, which is where customOAuthState is dispatched (derived from the state param) right before the signInWithRedirect success event:

if (isCustomState(state)) {
  Hub.dispatch(
    'auth',
    {
      event: 'customOAuthState',
      data: urlSafeDecode(getCustomState(state)),
    },
    'Auth',
    AMPLIFY_SYMBOL,
  );
}
Hub.dispatch('auth', { event: 'signInWithRedirect' }, 'Auth', AMPLIFY_SYMBOL);

We'd like to know if it's possible (or intentionally avoided) to dispatch customOAuthState from the error branch too, using the state param that's already on the error redirect URL — before dispatching signInWithRedirect_failure.

Describe the solution you'd like

In the error branch of completeOAuthFlow, read the state query param and dispatch customOAuthState (reusing the existing isCustomState/getCustomState helpers) before throwing, so that signInWithRedirect_failure listeners can still recover the custom state that was passed to signInWithRedirect:

if (error) {
  const state = urlParams.searchParams.get('state');
  if (state && isCustomState(state)) {
    Hub.dispatch(
      'auth',
      { event: 'customOAuthState', data: urlSafeDecode(getCustomState(state)) },
      'Auth',
      AMPLIFY_SYMBOL,
    );
  }
  throw createOAuthError(errorMessage ?? error);
}

We understand the error path deliberately skips validateState (there's no token exchange to validate against), so we wanted to flag explicitly that this reads customState from an unvalidated state param. From what we can tell, customState is treated by Amplify as an opaque, app-defined string with no security-sensitive use internally, so recovering it without validation seems low-risk — but we wanted to raise it in case there's a reason it's currently skipped that we're missing.

Describe alternatives you've considered

We currently work around this by stashing the value in sessionStorage before calling signInWithRedirect, and reading it back (with sessionStorage.removeItem) in our signInWithRedirect_failure handler. This works, but means we can't rely on the Hub event system alone for this — we wanted to check if there's a more idiomatic way we're missing, or if this workaround is the recommended approach.

Additional context

Use case: we pass a returnTo path (e.g. an invitation link the user arrived from) as customState so we can send the user back to where they started after signing in with Google:

await signInWithRedirect({ provider: "Google", customState: returnTo });

On success we read it back via customOAuthState and redirect accordingly. On failure (e.g. an existing native/email user mistakenly tries Google sign-in and our PreSignUp Lambda trigger blocks it with a friendly error message directing them back to email/password login), we'd like to redirect back to our login page with the same returnTo preserved so the original flow (e.g. accepting an invitation) isn't lost — but currently have no way to do this via the Hub event system.

Is this something that you'd be interested in working on?

  • 👋 I may be able to implement this feature request
  • ⚠️ This feature might incur a breaking change

Metadata

Metadata

Assignees

No one assigned

    Labels

    AuthRelated to Auth components/categoryfeature-requestRequest a new feature

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions