aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Unhandled Promise Rejection on OAuth for Auth0OAuthOpts #8870

Open cyim02 opened 3 years ago

cyim02 commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication

Amplify Categories

Not applicable

Environment information

``` # Put output below this line "@aws-amplify/api": "^4.0.14", "@aws-amplify/auth": "^4.3.4", "@aws-amplify/core": "^4.2.8", "react-native": "0.64.2" ```

Describe the bug

When using Auth0OAuthOpts rather than AwsCognitoOAuthOpts (shown below), an unhandled promise rejection error occurred.

Referenced: https://github.com/aws-amplify/amplify-js/blob/main/packages/auth/src/types/Auth.ts#L131

export interface AwsCognitoOAuthOpts { domain: string; scope: Array; redirectSignIn: string; redirectSignOut: string; responseType: string; options?: object; urlOpener?: (url: string, redirectUrl: string) => Promise; }

export function isCognitoHostedOpts( oauth: OAuthOpts ): oauth is AwsCognitoOAuthOpts { return (oauth).redirectSignIn !== undefined; }

export interface Auth0OAuthOpts { domain: string; clientID: string; scope: string; redirectUri: string; audience: string; responseType: string; returnTo: string; urlOpener?: (url: string, redirectUrl: string) => Promise; }

export type OAuthOpts = AwsCognitoOAuthOpts | Auth0OAuthOpts;

Expected behavior

Using Auth0OAuthOpts should behave the same as AwsCognitoOAuthOpts, such as opening the WebUI.

Reproduction steps

  1. Use below Amplify OAuth Config:

oauth: {

domain: auth0_domain, clientID: auth0_client_id, scope: 'email openid', redirectUri: auth0CallbackUri, responseType: 'code', returnTo: auth0CallbackUri,

},

  1. Call the below API

    Auth.federatedSignIn({customProvider: 'auth0'})

  2. An Unhandled Promise Rejection error occurred

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line WARN Possible Unhandled Promise Rejection (id: 0): TypeError: Cannot read property 'oauthSignIn' of undefined ```

aws-exports.js

No response

Manual configuration

No response

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

No response

chrisbonifacio commented 3 years ago

Hi @thomasyim02 👋 thanks for raising this issue! May I ask what documentation you might've been following to set up your custom Auth0 flow so that I can reproduce the issue more closely? I can't seem to find any examples that include a customProvider property in the options for Auth.federatedSignIn() nor is it included in the interface for Auth0OAuthOpts.

This is the documentation I was able to find for using Auth0. Perhaps this might be helpful?

https://docs.amplify.aws/lib/auth/advanced/q/platform/js/#federate-with-auth0

hkjpotato commented 3 years ago

Hi @thomasyim02 Can you help me understand your use case a little more? Do you want to mainly use Auth0 to hold your users base, and hook it up with AWS service? In that case, you can follow the link from @chrisbonifacio to setup Auth0 in your IAM as an OpenID Connect Provider first, then get AWS credentials by

Auth.federatedSignIn(
    domain, // The Auth0 Domain,
    {
        token: idToken, // The id token from Auth0
        // expires_at means the timestamp when the token provided expires,
        // here we can derive it from the expiresIn parameter provided,
        // then convert its unit from second to millisecond, and add the current timestamp
        expires_at: exp * 1000 // the expiration timestamp
    },
    { 
        // the user object, you can put whatever property you get from the Auth0
        // for example:
        name, // the user name
        email, // Optional, the email address
        phoneNumber, // Optional, the phone number
    } 
).then(cred => {
    console.log(cred);
});
cyim02 commented 3 years ago

@chrisbonifacio @hkjpotato I was looking to use Cognito UserPool as the userbase and Auth0 as an OpenID Connect to the User Pool rather than IdentityPool. Just like the provider listed at CognitoHostedUIIdentityProvider that uses FederatedSignInOptions below, but rather I am using customProvider at FederatedSignInOptionsCustom also shown below. Highly appreciated on the help!

Reference: https://github.com/aws-amplify/amplify-js/blob/main/packages/auth/src/types/Auth.ts#L75

export enum CognitoHostedUIIdentityProvider { Cognito = 'COGNITO', Google = 'Google', Facebook = 'Facebook', Amazon = 'LoginWithAmazon', Apple = 'SignInWithApple', }

export type FederatedSignInOptions = { provider: CognitoHostedUIIdentityProvider; customState?: string; };

export type FederatedSignInOptionsCustom = { customProvider: string; customState?: string; };

hkjpotato commented 3 years ago

@thomasyim02 in that case, I think you first need to setup auth0 as a known IdP for user pool first https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-oidc-idp.html

cyim02 commented 3 years ago

@hkjpotato yes, I did that. I discovered that if I do a state change at default config (AwsCognitoOAuthOpts) that requires the key "redirectSignin" plus the scope to be an array (which auth0 must return incorrect type):

oauth: {
   domain: auth0_domain,
   clientID: auth0_client_id,
   scope: ['email', 'openid'], // by looking at the AwsCognitoOAuthOpts types, this needs to be an array
   redirectSignIn: auth0CallbackUri,
   responseType: 'code',
   returnTo: auth0CallbackUri,
},

to the correct auth0 config (Auth0OAuthOpts) that I wanted to use below:

oauth: {
   domain: auth0_domain,
   clientID: auth0_client_id,
   scope: 'email openid', // by looking at the Auth0OAuthOpts types, this needs to be a string
   redirectUri: auth0CallbackUri,
   responseType: 'code',
   returnTo: auth0CallbackUri,
},`

the Login UI will show correctly, but if I don't do a state change on the config file, the error will occur. So, there should be a bug on using redirectUri instead of redirectSignIn. Requesting your help on this issue, appreciate!

chrisbonifacio commented 3 years ago

@thomasyim02 do you mean that you were able to get the auth0 signin working, but there is an issue with the Auth0OAuthOpts type definition?

cyim02 commented 3 years ago

@chrisbonifacio there is somewhere in the code that requires redirectSignIn prop to be used which it shouldn't when using redirectUri prop, such as Auth0OAuthOpts. Below shows more in detail, how can we get this isCognitoHostedOpts=false to work?

Reference: https://github.com/aws-amplify/amplify-js/blob/main/packages/auth/src/Auth.ts#L1969

const redirect_uri = isCognitoHostedOpts(this._config.oauth)
                    ? this._config.oauth.redirectSignIn
                    : this._config.oauth.redirectUri;
cwomack commented 1 year ago

@cyim02, after digging a little deeper into issue... it seems that the use of Cognito User Pools via Auth0 Federation isn't supported currently. Calling Auth.federatedSignIn() with Auth0 used for the OAuthOpts while CognitoHostedUI = false won't work and yield the "Unhandled Promise Rejection" error you are seeing.

While our docs state that the use of Identity Pools will work, there's no mention that Cognito User Pools will. As such, I'll change the labels from bug to feature request and be reviewing this further internally with the team.

Apologies for the delay and inconvenience, but we'll update this issue with any progress.