3
votes

My app first uses the Cognito LOGIN endpoint to obtain an Authorization Code. It then uses the TOKEN endpoint to try and obtain tokens (id_token, access_token, refresh_token) but that fails with unauthorized_client.

I do not understand why, the same client is used to access the LOGIN, and that succeeded in returning an authorization code. I'm following the documentation for the TOKEN endpoint

string clientId = ...
string clientSecret = ...
Uri redirectUri = new Uri("myapp://myhost");
string authorization_code = ... // obtained via HTTP GET on LOGIN endpoint
string accessTokenUrl = "https://<domain>.auth.<region>.amazoncognito.com/oauth2/token";

var queryValues = new Dictionary<string, string> 
{
    { "grant_type", "authorization_code" },
    { "code",  authorization_code },
    { "redirect_uri", redirectUri.AbsoluteUri },
    { "client_id", clientId},
};

using (HttpClient client = new HttpClient())
{ 
    // Authorization Basic header with Base64Encoded (clientId::clientSecret)
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
        "Basic",
Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(
    string.Format("{0}:{1}",
        clientId, 
        clientSecret))));

    // Url Encoded Content
    var content = new FormUrlEncodedContent(queryValues);

    // HTTPS POST
    HttpResponseMessage response = await client.PostAsync(accessTokenUrl, content).ConfigureAwait(false);

    string text = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    // test = {"error" : "unauthorized_client"}
}
1

1 Answers

1
votes

The problem is two-fold:

1- System.Uri.AbsoluteUri adds a trailing / in the returned string so that my redirectUri becomes myapp://myhost/ instead of myapp://myhost

2- AWS Cognito TOKEN endpoint does not accept trailing / in a redirectURI.

The solution:

I now call redirectUri.OriginalUri instead of redirectUri.AbsoluteUri where I build the query to preserve the redirectUri as it was when I built it.

(I don't really have control over this since in my case Xamarin.Auth.OAuthAuthenticator2 calls Uri.AbsoluteUri on my behalf and transforms the redirectUri string I gave it, so I'm going to have to fix Xamarin.Auth).