Skip to content

Instantly share code, notes, and snippets.

@ckimrie
Last active January 6, 2019 11:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ckimrie/96e4992036c559c1f046476d3fc16a7e to your computer and use it in GitHub Desktop.
Save ckimrie/96e4992036c559c1f046476d3fc16a7e to your computer and use it in GitHub Desktop.
How to use AWS Cognito to sign an http request to a custom AWS Api Gateway using IAMs Authorization.
//---- Angular 2 Http Service Example ----
import {Injectable} from "@angular/core";
import {Http, Headers} from "@angular/http";
const AWS = require("aws-sdk");
@Injectable()
export class ApiGatewayService {
constructor(private http:Http){
let creds = new AWS.CognitoIdentityCredentials({
IdentityPoolId: "eu-west-1:xxx-xxxx-xxxxxxxx"
});
AWS.config.update({
region: 'eu-west-1',
credentials: creds
});
AWS.config.credentials.get((err) => {
if(err) throw err;
let httpRequest = new AWS.HttpRequest("https://xxxxx.execute-api.eu-west-1.amazonaws.com/v1/my/api", "eu-west-1");
httpRequest.method = "POST";
httpRequest.headers.host = "xxxxx.execute-api.eu-west-1.amazonaws.com";
httpRequest.headers['Content-Type'] = "application/json";
httpRequest.body = JSON.stringify({
data: {
username: 'foo',
password: 'bar',
applicationName: 'biz',
}
});
let v4signer = new AWS.Signers.V4(httpRequest, "execute-api", true);
v4signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());
//Create a headers object from the AWS signed request
let headers = new Headers();
for(let key of Object.keys(httpRequest.headers)){
headers.set(key, httpRequest.headers[key]);
}
headers.delete('host'); //Browser throws a warning if attempting to set host header
this.http.post(httpRequest.endpoint.href, httpRequest.body, {
method: httpRequest.method,
search: httpRequest.endpoint.search,
headers: headers
}).subscribe((data)=>{
console.log(data); //Success
});
})
}
}
//---- Complete code example to sign AWS Http request ----
//Configure AWS
AWS.config.update({
region: 'eu-west-1',
//CognitoIdentityCredentials only needed if using Cognito. Use credentials specific to your usecase
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: "eu-west-1:xxxx-xxxxx-xxxxxxx"
});
});
//Create an HttpRequest representation of your request (this wont actually _DO_ the request)
var httpRequest = new AWS.HttpRequest("https://xxxxxxx.execute-api.eu-west-1.amazonaws.com/uri/to/method", "eu-west-1");
//REQUIRED
//Host & content type headers must be set
httpRequest.headers.host = "xxxxxxx.execute-api.eu-west-1.amazonaws.com"; //Host of the API being called
httpRequest.headers['Content-Type'] = "application/json";
//OPTIONAL
httpRequest.method = "GET"; //Default is POST
httpRequest.headers['x-biz'] = 'baz'; //Additional headers
httpRequest.body = JSON.stringify({foo:'bar'}); //Body must be a string if being used
//Instruct cognito credentials to get access, secret and session keys (only needs to be done once on page load)
AWS.config.credentials.get(function(err){
//Sign the request with the newly fetched credentials. All IAM Authorised API Gateway requests use the V4 signer
var v4signer = new AWS.Signers.V4(httpRequest, "execute-api", true);
v4signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());
//The httpRequest has now been signed with the credentials. You can pick it apart and use your own AJAX/Fetch library
//The AWS.HttpRequest itself isn't able to make the request on its own
console.log(httpRequest.headers) // { authorization: 'AWS4-HMAC-SHA256 Credential=ASIA...', x-amz-security-token:'AgoGb...', ...}
console.log(httpRequest.method) // GET
console.log(httpRequest.endpoint.href) // https://xxxxxxx.execute-api.eu-west-1.amazonaws.com/uri/to/method
console.log(httpRequest.body)
});
@ckimrie
Copy link
Author

ckimrie commented Feb 28, 2017

Here's an example of how to use the above to sign a request with the Angular 2 Http library:

import {Injectable} from "@angular/core";
import {Http, Headers} from "@angular/http";
const AWS = require("aws-sdk");

@Injectable()
export class ApiGatewayService {

  constructor(private http:Http){

    let creds = new AWS.CognitoIdentityCredentials({
      IdentityPoolId: "eu-west-1:xxx-xxxx-xxxxxxxx"
    });

    AWS.config.update({
      region: 'eu-west-1',
      credentials: creds
    });

    AWS.config.credentials.get((err) => {
      if(err) throw err;

      let httpRequest = new AWS.HttpRequest("https://xxxxx.execute-api.eu-west-1.amazonaws.com/v1/my/api", "eu-west-1");
      httpRequest.method = "POST";
      httpRequest.headers.host = "xxxxx.execute-api.eu-west-1.amazonaws.com";
      httpRequest.headers['Content-Type'] = "application/json";
      httpRequest.body = JSON.stringify({
        data: {
          username: 'foo',
          password: 'bar',
          applicationName: 'biz',
        }
      });

      let v4signer = new AWS.Signers.V4(httpRequest, "execute-api", true);
      v4signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());

      //Create a headers object from the AWS signed request
      let headers = new Headers();
      for(let key of Object.keys(httpRequest.headers)){
        headers.set(key, httpRequest.headers[key]);
      }
      headers.delete('host'); //Browser throws a warning if attempting to set host header

      this.http.post(httpRequest.endpoint.href, httpRequest.body, {
        method: httpRequest.method,
        search: httpRequest.endpoint.search,
        headers: headers
      }).subscribe((data)=>{
        console.log(data); //Success
      });
    })
  }
}

@balassy
Copy link

balassy commented Oct 9, 2017

Hello Christopher,

Thanks for sharing this solution, however this does not work any more, because the AWS.Signers class is not public in the current version of the SDK. See aws/aws-sdk-js#1247. This may be the solution: https://github.com/mhart/aws4.

Hope this helps,
György

@aussiearef
Copy link

Is this code safe? It has username and password in the client-side script??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment