Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Created January 2, 2018 16:33
Show Gist options
  • Save salrashid123/9810b45387adbd45a22bb4e17bdbe9d5 to your computer and use it in GitHub Desktop.
Save salrashid123/9810b45387adbd45a22bb4e17bdbe9d5 to your computer and use it in GitHub Desktop.
Getting a google id token in golang for cloud endpoints and identity proxy
package main
import (
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jws"
oauthsvc "google.golang.org/api/oauth2/v2"
"google.golang.org/grpc/credentials/oauth"
)
func doExchange(token string) (string, error) {
d := url.Values{}
d.Set("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
d.Add("assertion", token)
client := &http.Client{}
req, err := http.NewRequest("POST", "https://www.googleapis.com/oauth2/v4/token", strings.NewReader(d.Encode()))
if err != nil {
return "", err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func main() {
log.Println("Using gcloud ADC: ")
src, err := google.DefaultTokenSource(oauth2.NoContext, oauthsvc.UserinfoEmailScope)
if err != nil {
log.Fatalf("Unable to acquire token source: %v", err)
}
creds := oauth.TokenSource{src}
tok, err := creds.Token()
if err != nil {
log.Fatalf("Unable to acquire token source: %v", err)
}
if tok.Extra("id_token") != nil {
log.Printf("id_token: ", tok.Extra("id_token").(string))
}
/*************************************************************************/
log.Println("------------------------------------------")
log.Println("Using ServiceAccount JSON: ")
data, err := ioutil.ReadFile("/home/srashid/gcp_misc/certs/GCPNETAppID-e65deccae47b.json")
if err != nil {
log.Fatal(err)
}
log.Println("Using ServiceAccount JWTAccessTokenSourceFromJSON ")
// this will acquire a jwt signed by the local service account
jwt_access_token, err := google.JWTAccessTokenSourceFromJSON(data, "https://www.googleapis.com/oauth2/v4/token")
if err != nil {
log.Fatal(err)
}
t, err := jwt_access_token.Token()
if err != nil {
log.Fatal(err)
}
// exchanging it won't work as the 'scope' field or target_audience isn't set
jwt_access, err := doExchange(t.AccessToken)
if err != nil {
log.Fatal(err)
}
log.Println(jwt_access)
log.Println("Using ServiceAccount JWTConfigFromJSON and manually signed JWT ")
conf, err := google.JWTConfigFromJSON(data, oauthsvc.UserinfoEmailScope)
if err != nil {
log.Fatal(err)
}
header := &jws.Header{
Algorithm: "RS256",
Typ: "JWT",
KeyID: conf.PrivateKeyID,
}
// for iap/endpoints
private_claims := map[string]interface{}{"target_audience": "https://yourapp.appspot.com/"}
iat := time.Now()
exp := iat.Add(time.Hour)
payload := &jws.ClaimSet{
Iss: conf.Email,
Iat: iat.Unix(),
Exp: exp.Unix(),
Aud: "https://www.googleapis.com/oauth2/v4/token",
PrivateClaims: private_claims,
}
// from https://github.com/golang/oauth2/blob/master/internal/oauth2.go#L23
key := conf.PrivateKey
block, _ := pem.Decode(key)
if block != nil {
key = block.Bytes
}
parsedKey, err := x509.ParsePKCS8PrivateKey(key)
if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil {
log.Fatal("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
}
}
parsed, ok := parsedKey.(*rsa.PrivateKey)
if !ok {
log.Fatal("private key is invalid")
}
token, err := jws.Encode(header, payload, parsed)
if err != nil {
log.Fatal(err)
}
log.Println("Signed ID_token to exchange: ")
log.Println(token)
body, _ := doExchange(token)
log.Println("Exchanged Google_ID_TOKEN:", string(body))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment