Skip to content

signInWithRedirect always sends identity_provider=COGNITO, preventing Cognito from resuming a federated session #14897

Description

@jeremyswensen

Before opening, please confirm:

JavaScript Framework

Angular

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

None

Environment information

Details
# Put output below this line
System:
    OS: Windows 11 10.0.26200
    CPU: (24) x64 13th Gen Intel(R) Core(TM) i7-13700HX
  Binaries:
    Node: 24.0.0
    npm: 11.3.0
  Browsers:
    Chrome: 150.0.7871.184
  npmPackages:
    @angular/core: ^21.1.0 => 21.1.0
    aws-amplify: ^6.16.2 => 6.16.2
    typescript: ~5.9.3 => 5.9.3

@aws-amplify/auth resolves to 6.19.1 

Describe the bug

Description

signInWithRedirect() unconditionally adds an identity_provider parameter to the /oauth2/authorize request. When the caller does not specify a provider, Amplify defaults the value to COGNITO.

Cognito treats identity_provider as an explicit provider selector. According to the authorization endpoint documentation:

If you include an identity_provider or idp_identifier parameter in the URL, it silently redirects your user to the sign-in page for that identity provider.

As a result, Cognito will silently resume an existing managed-login session only when that session was established through the selected provider.

This means a user who originally signed in through a federated identity provider cannot be silently resumed by Amplify. The user still has a valid Cognito managed-login session, and Cognito successfully resumes that session when identity_provider is omitted. However, because Amplify always sends identity_provider=COGNITO, Cognito scopes the request to the native provider and returns the user to the sign-in page.

This affects ordinary sign-in behavior and also makes options.prompt = 'NONE' unusable for silent SSO, which is the scenario where session resumption matters most.

Evidence

I tested the full matrix against a production user pool in a single browser session.

Each session was established using a forced sign-in with prompt=login, ensuring that the authentication provider was unambiguous. I then issued requests directly to /oauth2/authorize to isolate the effect of the identity_provider parameter.

Session established through | No identity_provider | identity_provider=COGNITO -- | -- | -- Native username/password | Authorization code returned | Authorization code returned Google federation | Authorization code returned | error=login_required

Only one combination fails: a federated session combined with identity_provider=COGNITO. This is also the request Amplify currently emits when no provider is explicitly supplied.

The successful native-session result with identity_provider=COGNITO also rules out the alternative explanation that Cognito does not honor prompt=none. Cognito does honor it, but only when the supplied provider selector matches the provider used to establish the session.

Environment

  • Cognito managed login branding

  • Native username/password authentication enabled

  • Google federation configured

  • Microsoft OIDC configured

  • Sign in with Apple configured

  • @aws-amplify/auth: 6.19.1

  • The same unconditional identity_provider behavior is present on main

## Description

signInWithRedirect() unconditionally adds an identity_provider parameter to the /oauth2/authorize request. When the caller does not specify a provider, Amplify defaults the value to COGNITO.

Cognito treats identity_provider as an explicit provider selector. According to the [authorization endpoint documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html):

If you include an identity_provider or idp_identifier parameter in the URL, it silently redirects your user to the sign-in page for that identity provider.

As a result, Cognito will silently resume an existing managed-login session only when that session was established through the selected provider.

This means a user who originally signed in through a federated identity provider cannot be silently resumed by Amplify. The user still has a valid Cognito managed-login session, and Cognito successfully resumes that session when identity_provider is omitted. However, because Amplify always sends identity_provider=COGNITO, Cognito scopes the request to the native provider and returns the user to the sign-in page.

This affects ordinary sign-in behavior and also makes options.prompt = 'NONE' unusable for silent SSO, which is the scenario where session resumption matters most.

Evidence

I tested the full matrix against a production user pool in a single browser session.

Each session was established using a forced sign-in with prompt=login, ensuring that the authentication provider was unambiguous. I then issued requests directly to /oauth2/authorize to isolate the effect of the identity_provider parameter.

Session established through No identity_provider identity_provider=COGNITO
Native username/password Authorization code returned Authorization code returned
Google federation Authorization code returned error=login_required

Only one combination fails: a federated session combined with identity_provider=COGNITO. This is also the request Amplify currently emits when no provider is explicitly supplied.

The successful native-session result with identity_provider=COGNITO also rules out the alternative explanation that Cognito does not honor prompt=none. Cognito does honor it, but only when the supplied provider selector matches the provider used to establish the session.

Environment

  • Cognito managed login branding
  • Native username/password authentication enabled
  • Google federation configured
  • Microsoft OIDC configured
  • Sign in with Apple configured
  • @aws-amplify/auth: 6.19.1
  • The same unconditional identity_provider behavior is present on main

Expected behavior

Expected behavior

When the caller does not supply a provider, Amplify should omit identity_provider entirely so Cognito can resume whichever valid session exists, regardless of how it was established. Callers who want to target a specific provider already do so by passing provider.

Actual behavior

Amplify always sends identity_provider=COGNITO, which scopes the authorization request to the native Cognito provider and prevents existing federated sessions from being resumed.

Reproduction steps

Reproduction steps

This requires:

  • A Cognito user pool using managed login branding
  • At least one federated identity provider, such as Google
  • Two origins registered as callback URLs on the same app client
  1. Sign in through the federated identity provider on origin A.

  2. On origin B, where Amplify has no authentication tokens in localStorage, call:

    signInWithRedirect({
      options: {
        prompt: 'NONE',
      },
    });
  3. Amplify issues an authorization request containing:

    GET /oauth2/authorize?...&identity_provider=COGNITO&prompt=none
    
  4. Cognito redirects to the callback URL with:

    ?error=login_required&error_description=Login+required
    

    This occurs even though the browser has a valid Cognito managed-login session.

  5. Issue the same authorization request manually, but omit identity_provider. Cognito returns an authorization code.

  6. Repeat steps 1 through 5 using a native username/password session. In that case, both requests return an authorization code.

This is not a minimal reproduction in the usual sense because it requires a real Cognito user pool with a configured federated identity provider. However, the test matrix in the description isolates identity_provider as the only differing query parameter, and step 6 serves as a control demonstrating that prompt=none itself is supported.

Code Snippet

Caller — no provider specified, the intent being "resume whatever session exists":

import { signInWithRedirect } from 'aws-amplify/auth';

signInWithRedirect({ options: { prompt: 'NONE' } });

Library — packages/auth/src/providers/cognito/apis/signInWithRedirect.ts:

let provider = 'COGNITO'; // Default
...
if (idpIdentifier) {
    params.append('idp_identifier', idpIdentifier);
} else {
    params.append('identity_provider', provider);   // always appended
}

identity_provider is omitted only when idpIdentifier is supplied, which is itself a provider selector — so there is no way through the public API to issue an authorize request with neither parameter.

Log output

Details
// Put your logs below this line


aws-exports.js

No response

Manual configuration

Configured directly via Amplify.configure (no aws-exports):

{
  "Auth": {
    "Cognito": {
      "userPoolId": "<pool id>",
      "userPoolClientId": "<client id>",
      "loginWith": {
        "oauth": {
          "domain": "<managed login domain>",
          "scopes": ["openid", "email", "profile"],
          "redirectSignIn": ["https://site-a.example.com/auth/callback"],
          "redirectSignOut": ["https://site-a.example.com/"],
          "responseType": "code"
        }
      }
    }
  }
}

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

Suggested fix

Track whether the caller explicitly supplied a provider, and append identity_provider only when one was provided:

let provider: string | undefined;

if (typeof input?.provider === 'string') {
    provider = cognitoHostedUIIdentityProviderMap[input.provider];
} else if (input?.provider?.custom) {
    provider = input.provider.custom;
} else if (input?.provider?.idpIdentifier) {
    ({ idpIdentifier } = input.provider);
}

...

if (idpIdentifier) {
    params.append('idp_identifier', idpIdentifier);
} else if (provider) {
    params.append('identity_provider', provider);
}

Callers who do not pass a provider already land on Cognito managed login. That is the documented behavior when identity_provider is omitted, so this change should not affect users who do not have an existing session.

It would only allow Cognito to resume an existing session regardless of whether that session was established through native authentication or a federated identity provider.

If changing the current default is considered a breaking change, an explicit opt-out under options would also address the issue.

Impact

This affects applications that support both native and federated authentication and are served from multiple origins or app clients.

Federated users are forced to authenticate again, while native users are silently resumed. From the application's perspective, this appears to be an inconsistent authentication defect and is difficult to trace back to Amplify's automatic identity_provider=COGNITO parameter.

In our case, the behavior was reported as a product defect and took approximately two months to isolate.

Related issues

The closest existing issues I found are:

None of these appear to describe the behavior reported here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    AuthRelated to Auth components/categorybugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions