Go-Lang Making API Gateway Call via login with AWS Cognito using AWS4 Signer

Go-Lang Making API Gateway Call via login with AWS Cognito using AWS4 Signer


Below is the sample code to making AWS API Gateway call using AWS4 signer 

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/credentials"
	"io/ioutil"
	"net/http"
	"time"
)

// SignHTTP signs AWS v4 requests with the provided payload hash, service name, region the
// request is made to, and time the request is signed at. The signTime allows
// you to specify that a request is signed for the future, and cannot be
// used until then.
//
// The payloadHash is the hex encoded SHA-256 hash of the request payload, and
// must be provided. Even if the request has no payload (aka body). If the
// request has no payload you should use the hex encoded SHA-256 of an empty
// string as the payloadHash value.
//
//   "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
//
// Some services such as Amazon S3 accept alternative values for the payload
// hash, such as "UNSIGNED-PAYLOAD" for reque
var hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
var Region = "us-east-1"
var Host = "https://sandboxapi.mytest.com/"
var PoolId = "us-east-1_123456789"
var ClientId = "1234567890"
var ServiceName = "execute-api"
var IdentityPoolId = Region + ":e8682e09-e7ed-4247-827e-f4e1c7cc3578"

var LoginUrl = "https://cognito-idp." + Region + ".amazonaws.com"
var IdentityURL = "https://cognito-identity." + Region + ".amazonaws.com/"

var USERNAME = "test.user@testdomain.com"
var PASSWORD = "Test@123"

type AuthenticationResult struct {
	AccessToken  string `json:"AccessToken"`
	ExpiresIn    int64  `json:"ExpiresIn"`
	IdToken      string `json:"IdToken"`
	RefreshToken string `json:"RefreshToken"`
	TokenType    string `json:"TokenType"`
}

type LoginResponse struct {
	AuthenticationResult AuthenticationResult `json:"AuthenticationResult"`
}

type IdentityResponse struct {
	IdentityId string `json:"IdentityId"`
}

type Credentials struct {
	AccessKeyId  string `json:"AccessKeyId"`
	SecretKey    string `json:"SecretKey"`
	SessionToken string `json:"SessionToken"`
}
type CredentialsResponse struct {
	Credentials Credentials `json:"Credentials"`
}

func Login() AuthenticationResult {
	fmt.Println("Making Login Call to :- " + LoginUrl)
	client := &http.Client{}
	var obj LoginResponse
	var jsonStr = []byte(`{
    "AuthFlow": "USER_PASSWORD_AUTH",
    "ClientId": "` + ClientId + `",
    "AuthParameters": {
        "USERNAME": "` + USERNAME + `",
        "PASSWORD": "` + PASSWORD + `"
    },
    "ClientMetadata": {}
	}`)
	req, _ := http.NewRequest("POST", LoginUrl, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/x-amz-json-1.1")
	req.Header.Set("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth")
	loginResp, _ := client.Do(req)
	defer loginResp.Body.Close()
	bodyLogin, _ := ioutil.ReadAll(loginResp.Body)
	json.Unmarshal(bodyLogin, &obj)
	return obj.AuthenticationResult
}

func GetIdentityId(loginObj AuthenticationResult) IdentityResponse {
	fmt.Println("Making Identity Call to :- " + IdentityURL)
	client := &http.Client{}
	var obj IdentityResponse
	var jsonStr = []byte(`{
    	"IdentityPoolId": "` + IdentityPoolId + `",
    	"Logins": {
        	"cognito-idp.` + Region + `.amazonaws.com/` + PoolId + `": "` + loginObj.IdToken + `"
    	}
	}`)
	req, _ := http.NewRequest("POST", IdentityURL, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/x-amz-json-1.1")
	req.Header.Set("x-amz-target", "AWSCognitoIdentityService.GetId")
	loginResp, _ := client.Do(req)
	defer loginResp.Body.Close()
	bodyLogin, _ := ioutil.ReadAll(loginResp.Body)
	json.Unmarshal(bodyLogin, &obj)
	return obj
}

func GetCredentialsForIdentity(loginObj AuthenticationResult, identityObj IdentityResponse) Credentials {
	fmt.Println("Making Get Credentials Call to :- " + IdentityURL)
	client := &http.Client{}
	var obj CredentialsResponse
	var jsonStr = []byte(`{
		"IdentityId": "` + identityObj.IdentityId + `",
		"Logins": {
			"cognito-idp.` + Region + `.amazonaws.com/` + PoolId + `": "` + loginObj.IdToken + `"
		}
	}`)
	req, _ := http.NewRequest("POST", IdentityURL, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/x-amz-json-1.1")
	req.Header.Set("x-amz-target", "AWSCognitoIdentityService.GetCredentialsForIdentity")
	loginResp, _ := client.Do(req)
	defer loginResp.Body.Close()
	bodyLogin, _ := ioutil.ReadAll(loginResp.Body)
	json.Unmarshal(bodyLogin, &obj)
	return obj.Credentials
}

func GetRefreshToken(refreshToken string) AuthenticationResult {
	fmt.Println("Making Login Call refresh token to :- " + LoginUrl)
	client := &http.Client{}
	var obj LoginResponse
	var jsonStr = []byte(`{
    "AuthFlow": "REFRESH_TOKEN_AUTH",
    "ClientId": "` + ClientId + `",
    "AuthParameters": {
        "REFRESH_TOKEN": "` + refreshToken + `"
    },
    "ClientMetadata": {}
	}`)
	req, _ := http.NewRequest("POST", LoginUrl, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/x-amz-json-1.1")
	req.Header.Set("x-amz-target", "AWSCognitoIdentityProviderService.InitiateAuth")
	loginResp, _ := client.Do(req)
	defer loginResp.Body.Close()
	bodyLogin, _ := ioutil.ReadAll(loginResp.Body)
	json.Unmarshal(bodyLogin, &obj)
	return obj.AuthenticationResult
}

func MakeGetAPICall(credentiasObj Credentials, path string) string {
	host := Host + path
	fmt.Println("Making Get Call to :- " + host)
	client := &http.Client{}
	cfg, _ := config.LoadDefaultConfig(context.TODO(),
		config.WithCredentialsProvider(
			credentials.NewStaticCredentialsProvider(
				credentiasObj.AccessKeyId,
				credentiasObj.SecretKey,
				credentiasObj.SessionToken,
			),
		),
	)
	credentials, _ := cfg.Credentials.Retrieve(context.TODO())
	req, _ := http.NewRequest(http.MethodGet, host, nil)
	signer := v4.NewSigner()
	_ = signer.SignHTTP(context.TODO(), credentials, req, hash, ServiceName, Region, time.Now())
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	return string(body)
}

func main() {
	loginObj := Login()
	identityObj := GetIdentityId(loginObj)
	credentiasObj := GetCredentialsForIdentity(loginObj, identityObj)
	var refreshToken AuthenticationResult = GetRefreshToken(loginObj.RefreshToken)
	loginObj.AccessToken = refreshToken.AccessToken
	loginObj.IdToken = refreshToken.IdToken
	body := MakeGetAPICall(credentiasObj, "user/user-service/common/profile")
	fmt.Println("response Body:", string(body))
}

Steps in making API Gateway Calls:-

  • First We login via Cognito to get idToken.
  • Then we get AccessId, SecretId and SessionToken via AWS Cognito Identity Provider.
  • Then we get a Refresh Token to update the AccessToken and IdToken
  • Then we make a HTTP get call using AWS4 Signer.

Required Parameters:-

  • PoolId
  • AWS Cognito ClientId
  • Region
  • IdentityPoolId
  • Username/Password of Cognito
  • Host URL of AWS API Gateway

Comments

Popular posts from this blog

Setup AWS Cognito and Signup user using Postman

AWS IOT Create OTA With RollOut and Abort Configuration.

What is Amazon Cognito?