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

What is Amazon Cognito?

Setup AWS Cognito and Signup user using Postman

Rest API Testing Using Postman