Skip to content

Instantly share code, notes, and snippets.

@bsathishciv
Last active April 19, 2020 07:32
Show Gist options
  • Save bsathishciv/cee4069ac807ff77fe19274e41b856e4 to your computer and use it in GitHub Desktop.
Save bsathishciv/cee4069ac807ff77fe19274e41b856e4 to your computer and use it in GitHub Desktop.
Salesforce authentication module in Go lang
package authentication
import (
"bufio"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
)
const grantType string = "urn:ietf:params:oauth:grant-type:jwt-bearer"
const consumerKet string = "3MVG9ZLXXXXXXXXXXXXXXXXXXXXXXX_kyc" // replace with consumer key of the connected app
/ AuthenticationRequest - wrapper to hold auth request data
// OAuth 2.0. protocol is used
type AuthenticationRequest struct {
URL string `json:"url"`
Username string `json:"username"`
}
type authenticationResponse struct {
Token string `json:"access_token"`
InstanceURL string `json:"instance_url"`
ID string `json:"id"`
TokenType string `json:"token_type"`
IssuedAt string `json:"issued_at"`
Signature string `json:"signature"`
}
type claims struct {
jwt.StandardClaims
}
type AuthenticationResponse interface {
GetToken() string
GetInstanceURL() string
GetID() string
GetTokenType() string
GetIssuedAt() string
GetSignature() string
}
// GetToken returns the authenication token.
func (response authenticationResponse) GetToken() string { return response.Token }
// GetInstanceURL returns the Salesforce instance URL to use with the authenication information.
func (response authenticationResponse) GetInstanceURL() string { return response.InstanceURL }
// GetID returns the Salesforce ID of the authenication.
func (response authenticationResponse) GetID() string { return response.ID }
// GetTokenType returns the authenication token type.
func (response authenticationResponse) GetTokenType() string { return response.TokenType }
// GetIssuedAt returns the time when the token was issued.
func (response authenticationResponse) GetIssuedAt() string { return response.IssuedAt }
// GetSignature returns the signature of the authenication.
func (response authenticationResponse) GetSignature() string { return response.Signature }
// Authenicate will exchange the JWT signed request for access token.
func Authenicate(request AuthenticationRequest, client *http.Client) (AuthenticationResponse, error) {
privateKeyFile, err := os.Open("private_key.pem") // Give a relative reference to this file.
if err != nil {
return nil, err
}
pemfileinfo, _ := privateKeyFile.Stat()
var size int64 = pemfileinfo.Size()
pembytes := make([]byte, size)
buffer := bufio.NewReader(privateKeyFile)
_, err = buffer.Read(pembytes)
pemData := []byte(pembytes)
privateKeyFile.Close() // close file
expirationTime := time.Now().Add(3 * time.Minute)
claims := &claims{
StandardClaims: jwt.StandardClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: expirationTime.Unix(), // type int64
Audience: request.URL, // "https://test.salesforce.com" || "https://login.salesforce.com"
Issuer: request.ClientID, // consumer key of the connected app, hardcoded
Subject: request.Username, // username of the salesforce user, whose profile is added to the connected app
},
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
signKey, err := jwt.ParseRSAPrivateKeyFromPEM(pemData) // parse the RSA key
tokenString, err := token.SignedString(signKey) // sign the claims with private key
form := url.Values{}
form.Add("grant_type", grantType)
form.Add("assertion", tokenString)
url := request.URL + "/services/oauth2/token" // token endpoint for getting access token
log.Info("Performing request using url: " + url)
httpRequest, err := http.NewRequest("POST", url, strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
httpRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
response, respErr := client.Do(httpRequest)
if respErr != nil {
return nil, respErr
}
if response.StatusCode >= 300 {
return nil, errors.New(response.Status)
}
body, bodyErr := ioutil.ReadAll(response.Body)
if bodyErr != nil {
return nil, bodyErr
}
var jsonResponse authenticationResponse
unMarshallErr := json.Unmarshal(body, &jsonResponse)
if unMarshallErr != nil {
return nil, unMarshallErr
}
return jsonResponse, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment