title: How to exchange JWT token for Credentials in Cognito Identity Pool in .NET Core 3.1 WebApi
body: <p><strong>Broad Overview</strong>: I am trying to create a .Net Core 3.1 WebApi backend that is authenticated against Amazon Cognito. I want to use the Amazon-hosted sign-in page(s) provided by Cognito. I want to leverage Cognito Identity Pool to provide temporary scoped credentials for users after they have logged in. I cannot figure out how to exchange the Cognito token to create the Credentials to call AWS services.</p>
  <p><strong>Technology Overview</strong></p>
  <ul>
  <li>.NET Core 3.1 WebApi</li>
  <li>Amazon Cognito User Pool for initial authentication</li>
  <li>Amazon Identity Pool for defining permissions (Roles) for logged in users</li>
  <li>Deployed on AWS via API Gateway + Lambda using the AWS Serverless framework (basically CloudFormation)</li>
  </ul>
  <p>Currently both of the following work:</p>
  <ul>
  <li>Add [Authorize] attribute to a controller endpoint and access the URL in a browser. This re-directs me to the Cognito-hosted login page and, upon successful login, returns me back to the controller/endpoint and I am authorized.</li>
  <li>Create a separate Client application and login to AWS Cognito. Pass the JWT token in the Authorization HTTP header when calling APIs from the client and the Authorization succeeds and API access is granted.</li>
  </ul>
  <p>In both cases, the access to the API is permitted however the AmazonServiceClient instances that are created in the WebApi are granted the permissions associated with the Lambda function (which is the proper behavior).</p>
  <h2>Problem</h2>
  <p><strong>I need to create AmazonServiceClients whose credentials match the Role defined by the Cognito Identity Pool.</strong></p>
  <p>To do this, I need to exchange token provided by logging into Cognito User Pool for temporary credentials in the Identity Pool.</p>
  <p>Virtually ALL examples and documentation I can find on this process define how to manually login to Cognito using the API (not the hosted web UI), and then using the API response to create a CognitoUser and then get credentials from the Identity Pool using that user.</p>
  <p>The closest (though <em>super</em> brief) documentation I can find to do what I need is from AWS here: <a href="https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/cognito-creds-provider.html" rel="nofollow noreferrer">https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/cognito-creds-provider.html</a></p>
  <pre><code>// Authenticate user through Facebook
  string facebookToken = GetFacebookAuthToken();
  
  // Add Facebook login to credentials. This clears the current AWS credentials
  // and retrieves new AWS credentials using the authenticated role.
  credentials.AddLogin(&quot;graph.facebook.com&quot;, facebookAccessToken);
  </code></pre>
  <p>While that example uses Facebook, conceptually it should be the same for any provider (Facebook, Google, Twitter, OpenId, etc.).</p>
  <h2>My Current Attempt</h2>
  <p>I have registered CognitoAWSCredentials as a Scoped service as it is user-specific and therefore should only exist as long as the API request session exists.</p>
  <pre><code>RegionEndpoint region = Configuration.GetAWSOptions().Region;
  services.AddScoped(_ =&gt; new CognitoAWSCredentials(Settings.CognitoIdentityPoolId, region));
  </code></pre>
  <p>I have created an event handler that gets triggered when the OpenIdConnect event 'OnTokenValidated' is fired. This happens after I login to the Cognito hosted web UI and am redirected back to my API.</p>
  <p>In this handler I can call:</p>
  <pre><code>CognitoAWSCredentials creds = services.BuildServiceProvider().GetRequiredService&lt;CognitoAWSCredentials&gt;();
  creds.AddLogin( ... ??? ...);
  </code></pre>
  <p><em>(note: since I'm setting all this up in the <code>Startup.ConfigureServices(IServiceCollection services)</code> method, I am building an <code>IServiceProvider</code> instance each time authentication succeeds... which may be inefficient but I haven't figured out another way to access a scoped service inside the ConfigureServices method)</em></p>
  <p>All this preamble to say that I cannot find a set of values for the <code>AddLogin</code> call which allow this test call to succeed:</p>
  <pre><code>ImmutableCredentials immCreds = creds.GetCredentials();
  </code></pre>
  <h2>Relevant Data Structures</h2>
  <p>In the event handler where I can call AddLogin, I have access to: <code>Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext</code> which in particular contains:</p>
  <ul>
  <li><code>Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage</code> with:
  <ul>
  <li>access_token</li>
  <li>id_token</li>
  <li>refresh_token</li>
  </ul>
  </li>
  <li><code>System.IdentityModel.Tokens.Jwt.JwtSecurityToken</code> with:</li>
  </ul>
  <pre><code>{
      {
          &quot;alg&quot;: &quot;RS256&quot;,
          &quot;kid&quot;: &quot;**************************&quot;
      }. {
          &quot;at_hash&quot;: &quot;**************************&quot;,
          &quot;sub&quot;: &quot;**************************&quot;,
          &quot;email_verified&quot;: true,
          &quot;iss&quot;: &quot;https://cognito-idp.ca-central-1.amazonaws.com/**************************&quot;,
          &quot;cognito:username&quot;: &quot;**************************&quot;,
          &quot;nonce&quot;: &quot;**************************&quot;,
          &quot;aud&quot;: &quot;**************************&quot;,
          &quot;event_id&quot;: &quot;**************************&quot;,
          &quot;token_use&quot;: &quot;id&quot;,
          &quot;auth_time&quot;: 1595260191,
          &quot;exp&quot;: 1595263791,
          &quot;iat&quot;: 1595260191,
          &quot;email&quot;: &quot;**************************&quot;
      }
  }
  </code></pre>
  <p>I have tried using the <code>iss</code> value as the providerName in AddLogin, and either the <code>access_token</code> or <code>id_token</code> but neither work.</p>
  <p><strong>Does anyone know what I need to use for AddLogin in order for Cognito to create Identity Pool credentials for me based upon a JWT token from a Cognito User Pool login?</strong></p>