aws-amplify / amplify-swift

A declarative library for application development using cloud services.
Apache License 2.0
449 stars 194 forks source link

API Gateway Cognito User Pool 401 #877

Closed nkb1337 closed 3 years ago

nkb1337 commented 3 years ago

Hello,

I am trying to fetch data from an API Gateway endpoint with an custom authorizer (Cognito User Pool).

However, I successfully logged in via amplify I get an 401 whenever I try to send an request to whatever endpoint

Thats my amplifyconfiguration

{ "auth": { "plugins": { "awsCognitoAuthPlugin": { "UserAgent": "aws-amplify/cli", "Version": "0.1.0", "IdentityManager": { "Default": {} }, "CognitoUserPool": { "Default": { "PoolId": "eu-central-1_XXXX", "AppClientId": "XX", "AppClientSecret": "XX", "Region": "eu-central-1" } }, "CredentialsProvider": { "CognitoIdentity": { "Default": { "PoolId": "eu-central-1XXX", "Region": "eu-central-1" } } }, "Auth": { "Default": { "authenticationFlowType": "USER_SRP_AUTH", } } } } }, "api": { "plugins": { "awsAPIPlugin": { "shipsoul": { "endpointType": "REST", "endpoint": "https://XXXXXX", "region": "eu-central-1", "authorizationType": "AMAZON_COGNITO_USER_POOLS" } } } } }

Using latest version of Amplify

Device Information (please complete the following information): iphone SE / 11 / 12 iOS 14

lawmicha commented 3 years ago

Hi @nkb1337

formatting your amplifyconfiguration.json using triple backticks

{
   "auth":{
      "plugins":{
         "awsCognitoAuthPlugin":{
            "UserAgent":"aws-amplify/cli",
            "Version":"0.1.0",
            "IdentityManager":{
               "Default":{

               }
            },
            "CognitoUserPool":{
               "Default":{
                  "PoolId":"eu-central-1_XXXX",
                  "AppClientId":"XX",
                  "AppClientSecret":"XX",
                  "Region":"eu-central-1"
               }
            },
            "CredentialsProvider":{
               "CognitoIdentity":{
                  "Default":{
                     "PoolId":"eu-central-1XXX",
                     "Region":"eu-central-1"
                  }
               }
            },
            "Auth":{
               "Default":{
                  "authenticationFlowType":"USER_SRP_AUTH"
               }
            }
         }
      }
   },
   "api":{
      "plugins":{
         "awsAPIPlugin":{
            "shipsoul":{
               "endpointType":"REST",
               "endpoint":"https://XXXXXX",
               "region":"eu-central-1",
               "authorizationType":"AMAZON_COGNITO_USER_POOLS"
            }
         }
      }
   }
}

The configuration looks good to me. After sign in, you can get the token and use it to test connectivity in the API Gateway console.

Get the token https://docs.amplify.aws/lib/auth/access_credentials/q/platform/ios

if let cognitoTokenProvider = session as? AuthCognitoTokensProvider {
            let tokens = try cognitoTokenProvider.getCognitoTokens().get()
            print("Id token - \(tokens.idToken) ") 
        }

I've outlined my experience here aws-amplify/amplify-category-api#345

Once you can verify this, there's another thing to watch out for; the api configuration with AMAZON_COGNITO_USER_POOLS authorizationType will intercept the request with the accessToken and Not the idToken. If you require the idToken, you'll have to follow these steps to introduce your own token provider under OIDC authorizationType. See https://docs.amplify.aws/lib/restapi/authz/q/platform/ios#oidc for more details.

nkb1337 commented 3 years ago

Hi,

I think I found the issue(?). When I send a request instantly after signing it seems like there is no session available. (Obtaining an identity id in another thread failed or didn't complete within 5 seconds.")

However after couple of seconds I can send the requests without any issues and an session is available and I can get the tokens etc. without any issues.

royjit commented 3 years ago

Hi @nkb1337

Thank you for providing this information. When you say that you send a request instantly after signIn, are you calling it in signIn callback? Like this:

1)

Amplify.Auth.signIn(username: "", password: "") { (result) in
            // Call api request here 
}

Or outside the callback? Something like this: 2)

Amplify.Auth.signIn(username: "", password: "") 
// Call api request here 

You should follow # 1 approach ie wait for the signIn to complete before invoking api request. Can you provide a code snippet on how and when you invoke the api request to help us debug further.

wedouglas commented 3 years ago

@lawmicha I'm having some similar issues. I've followed all the steps provided by documentation, but API Gateway doesn't seem to accept access tokens. AWS says that you can use access tokens if you enable OAuth scopes, but when you enable OAuth scopes, it seems like it changes from looking for the id token to looking for what appears to be an AWS Version 4 Signature.

Nothing I do seems to work with these Cognito access tokens. I know all the paths are correct because when I delete the OAuth scopes, I can use Postman with the id token in the header and the gateway works and responds correctly. The moment I try to use OAuth scopes though, neither id tokes or access tokens work anymore. It's driving me crazy.

This is the response I get when OAuth scopes are used:

403 Forbidden "Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=myaccesstoken..."

Any idea?

github-actions[bot] commented 3 years ago

This issue is stale because it has been open for 14 days with no activity. Please, provide an update or it will be automatically closed in 7 days.

royjit commented 3 years ago

@wedouglas Just to confirm, did you follow the steps as mentioned in this GH issue - aws-amplify/amplify-category-api#345 . There seems to be some manual steps as mentioned in step 7 to 11.

wedouglas commented 3 years ago

@royjit We were able to figure it out a while back. I don't recall offhand what we ended up changing, but I think our issue was just the documentation being unclear for how you call the API. We were calling it with the custom scope in the endpoint url since that's what the documentation showed as an example.

I think it's just another case of AWS documentation being, well, less than great haha.

In any case, thanks for your help after the fact!

iThink32 commented 3 years ago

@lawmicha i am facing a similar issue , i have an iOS project setup which uses cognito to authenticate users , it logs in successfully but all api's return 401.

I have followed all 11 steps and the concerning part is this is happening after i updated amplify to the following

Installing AWSAuthCore 2.25.0 (was 2.14.2)
Installing AWSCognitoIdentityProvider 2.25.0 (was 2.14.2)
Installing AWSCognitoIdentityProviderASF 2.25.0 (was 1.0.1)
Installing AWSCore 2.25.0 (was 2.14.2)
Installing AWSMobileClient 2.25.0 (was 2.14.2)
Installing AWSPluginsCore 1.13.4 (was 1.0.4)
Installing AWSS3 2.25.0 (was 2.14.2)
Installing Amplify 1.13.4 (was 1.0.4)
Installing AmplifyPlugins 1.13.4 (was 1.0.4)
Installing AppSyncRealTimeClient 1.5.0 (was 1.1.6)

The earlier version is also provided above.

If i switch back to the earlier version of amplify plugins it works fine.Can you pls help me out?