0
votes

I'm develop app IOS and Android with Xamarin cross-platform. I'm trying hard to use credentials receiving from Cognito Identity to authorize app invoking API Gateway.

My user flow is:

  1. Authenticate on Cognito User Pool and get tokens
  2. Exchange tokens for credentials on Cognito Identity Pools
  3. Access API Gateway using credentials retrieved in the previous step.

Step 1 and 2 seems to works fine. But when app try to connect to api gateway it's getting error 403 (Forbidden).

My code:

  1. Authenticate on Cognito User Pool and get tokens

**

public async Task<AppUser> Login(string username, string password)   
 {
        CognitoUser cognitoUser = new CognitoUser(username, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient);
        AppUser appUser = new AppUser() { Email = username };
        // Send a login request and wait for the response from Amazon
        try
        {
            AuthFlowResponse response = await cognitoUser.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
            {                    
                Password = password
            });
            ;
            appUser.IsAuthenticated = true;
        }
        catch (NotAuthorizedException e)
        {
            appUser.IsAuthenticated = false;
            appUser.ErrorMessage = e.Message;
        }
        await _tokenManagement.SaveTokens(cognitoUser.SessionTokens) ;
        return appUser;
    }
  1. Exchange tokens for credentials on Cognito Identity Pools

**

public async Task<ImmutableCredentials> GetAppCredentialsAsync()
{
    CognitoAWSCredentials cac;
        
        if (_tokenManagement.CheckIsAnonymous())
        {
            //Anonymous credentials        
            cac = new CognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1); 
        }
        else
        {
            //Retrieve saved tokens from previous authentication
            var tm = await _tokenManagement.RetrieveTokens();
        
            CognitoUser user = new CognitoUser(null, Aws.COGNITO_CLIENT_ID, CognitoUserPool, CognitoIdentityProviderClient)
            {
                    SessionTokens = new CognitoUserSession(tm.IdToken, tm.AccessToken, tm.RefreshToken, tm.IssuedTime, tm.ExpirationTime)
            };
            //Retrieve authenticated credentials
            cac = user.GetCognitoAWSCredentials(Aws.COGINITO_IDENTITY_POLL_ID, RegionEndpoint.USEast1);
        
        }
                       
     }
                 
    return await cac.GetCredentialsAsync();
        
}
  1. Access API Gateway using credentials retrieved in the previous step:

**

public async Task<IList<MediaImage>> GetCoversAWSAsync()
    {
        // Getting credentials and sign request
        var request = await BuildRequestAsync("/listMedia");
        
        var client = new HttpClient();
        
        var response = await client.SendAsync(request);
        response.EnsureSuccessStatusCode();
    
        IList<MediaImage> covers = JsonConvert.DeserializeObject<IList<MediaImage>>(await response.Content.ReadAsStringAsync());
    
        return covers;
    
    }
    
    private async Task<HttpRequestMessage> BuildRequestAsync(string service)
    {
    
        var request = new HttpRequestMessage()
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(baseURL + service)
            
        };   
        
        ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );
                       
    
        var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
    
        request = await signer.Sign(request, "execute-api", awsRegion);
    
    
        return request;
    
    }

This code works fine when I hard code credentials from one IAM user. But credentials retrieved from Cognito Identities its getting Forbidden error. I did a test using SDK for S3 and I was able to successfully list the buckets with the same credentials received from Cognito Identities, but it is not possible to make requests on the API Gateway.

Can you help me? Where did I get lost?

1

1 Answers

0
votes

I figure out what was going on.

After ensuring that the permissions settings were correct on AWS.

I found in the documentation that it is necessary to include in the HTTP header the token returned by the cognito (header name x-amz-security-token). So I changed the code to the following:

    private async Task<HttpRequestMessage> BuildRequestAsync(string service)
    {
    
        var request = new HttpRequestMessage()
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(baseURL + service)
            
        };   
        
        ImmutableCredentials awsCredential = await _loginService.GetAppCredentialsAsync( );

        //This where I add header to the HTTP request              
        request.Headers.Add("x-amz-security-token", awsCredential.Token);

        var signer = new AWS4RequestSigner(awsCredential.AccessKey, awsCredential.SecretKey);
    
        request = await signer.Sign(request, "execute-api", awsRegion);
    
    
        return request;
    
    }