Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active August 17, 2022 12:09
Show Gist options
  • Save salrashid123/c8283cdd7155bae3fdf53f3fe3abcfd8 to your computer and use it in GitHub Desktop.
Save salrashid123/c8283cdd7155bae3fdf53f3fe3abcfd8 to your computer and use it in GitHub Desktop.
golang-jwt parserver and keyfunc
package main
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"log"
"time"
jwt "github.com/golang-jwt/jwt/v4"
"github.com/lestrrat/go-jwx/jwk"
)
var (
jwtSet *jwk.Set
)
const (
jwksURL = "https://gist.githubusercontent.com/salrashid123/d4c9aa1c18c49eb60c8a4a8964d87f1a/raw/8f3fb1cb052017e66bcb53adc86dd1439e2f3adb/jwk"
keyID = "123456"
pubKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqrpBHkLN4vT6g279KYT
nnbKWHIEa+fK04wlamlrALQpV6QGfIrPwSgU/ElRFpsPJYWxCvEtYS01lBC70IeA
hObR5DY9Z+jTvhk1tA+VrxyEhAHLuCuCsAPLow4ZSJ+aB0vZuUtaV9+qO+0gyJEG
9y/5FKT51Tbr0INtjDASH43seoQtsPDG2tnKEj9r7jOLUNehj5j4Dgv+sJMGe3Ey
Klw7p6vsIhsU23v0VrTxdHGuelzplxCUQJoPRSxgepYyVmfrB12XJ5uJtLhYwuTb
Fb3BIUyswBtxtGcigvk/ftkuSQjubiXe8UtltBI7INfs7vmAVuQr7YN8Alni4Z3B
eQIDAQAB
-----END PUBLIC KEY-----`
privKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAqqrpBHkLN4vT6g279KYTnnbKWHIEa+fK04wlamlrALQpV6QG
fIrPwSgU/ElRFpsPJYWxCvEtYS01lBC70IeAhObR5DY9Z+jTvhk1tA+VrxyEhAHL
uCuCsAPLow4ZSJ+aB0vZuUtaV9+qO+0gyJEG9y/5FKT51Tbr0INtjDASH43seoQt
sPDG2tnKEj9r7jOLUNehj5j4Dgv+sJMGe3EyKlw7p6vsIhsU23v0VrTxdHGuelzp
lxCUQJoPRSxgepYyVmfrB12XJ5uJtLhYwuTbFb3BIUyswBtxtGcigvk/ftkuSQju
biXe8UtltBI7INfs7vmAVuQr7YN8Alni4Z3BeQIDAQABAoIBAG2SZSA2BnmXEGsI
fk/IAHiQk8DNEwGkQ5gmNi9nlwdQo+pcqL108YV1kmOXPrRgwQy6FLyNszDcsbVq
OOrc1Cp/duop2KrJ1IgL72q3RsaybHHEJWMMrE8NYMRC3QC/V0iv7g0Ez+/y7Xyj
9ZRPaEVzS1txv+Sf6i5o8wA6LKiMjMDYLFKxfzhjdakghshSNobuP3Vrw+KthHtr
96bTESBD/nvBJolZs8wiFa/DcXGrgoh2htZhuxlZCTsEMWT8TCETsZohR5NUZ0wL
yD2+KXwIydp2NIkunfKT7EISaZ1fNpPPjCMskpEL675yQklluo+D6qj9W1HDRkYk
zo7PEMECgYEA4cQddq3H6CftnLrg2QcDT3jOhxOnHCT31oQBHZbUNLpQ38fHp6BX
YnQ0bH32eFHYLw9TEdYhwebp2rLruPjy25r8buRK+YXkhNL404ooo9dC1XhX7oVz
6aMVq6yHSlNsNrbTXH1CChP/9hgPR5osfeUP8u2Utp7exQg9qE/zmr0CgYEAwYXe
J0LWmXknnqZ/8Ld7ZKZiL7U9E5QV8Epz9OYCHDQevRoh03iWhUWJeP1ps0sp1rb8
zW3kUs5iCzj54UylcwcPYLK9hgVsYtgLFbNas9XwdNPQH0OdlUBAtAIvyZudIVCb
vJyCcuw/KlUIbDDI23n3/sqiM60H0H9u+FOFy20CgYAV7vap1AJK5K4p/uHfU9YX
f3YZG2itzE2jspllJYUiRkObKg6Uk3hJ4V5CeA5c7B6jm8qHPhVzgBqSG7XY956o
hSsnHtjF2yMzYEe6TX7bRAuDL7jjPGXhee2eCxntt6MYwbRRFP44em7wmq/JVgoi
hQGCqWA8Sbz8yWssEfBpxQKBgGgc1wmUQdPLhG8r8ETW0YGyqbw06yjvUGY4B+5H
F/eIaskdl/knNQN6B52Z6BXXaCjlxVfXuTB7a+/RtU1qaNBbigBh6OiDXm5HAJ+q
IDAD9xtDIQLQ46R6LtUpIAB8wao8raxpHx0o0Eq7+I4MKOM62RqwdVcLzdpz1IWw
mZh5AoGAeVkFstY9lmcdEi2rHUAsR2WMOnzYP4WS+/dYIMsXVryNVa/obbjwz94N
rWWOI9aKV6wvK+CIzHsI7hsFw7aF0S2x1gg4RvtxDgHCMbgI3t8tdCtph7cmDKNp
W1NUvPpHH7t1YenNODRZSEo/ETn69WX6i0kV4BNI64+cU60pUwQ=
-----END RSA PRIVATE KEY-----`
)
type gcpIdentityDoc struct {
Google struct {
ComputeEngine struct {
InstanceCreationTimestamp int64 `json:"instance_creation_timestamp,omitempty"`
InstanceID string `json:"instance_id,omitempty"`
InstanceName string `json:"instance_name,omitempty"`
ProjectID string `json:"project_id,omitempty"`
ProjectNumber int64 `json:"project_number,omitempty"`
Zone string `json:"zone,omitempty"`
} `json:"compute_engine"`
} `json:"google"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
AuthorizedParty string `json:"azp,omitempty"`
jwt.StandardClaims
}
func main() {
privatePEM := []byte(privKey)
rblock, _ := pem.Decode(privatePEM)
r, err := x509.ParsePKCS1PrivateKey(rblock.Bytes)
if err != nil {
fmt.Println(err)
return
}
claims := gcpIdentityDoc{
Email: "[email protected]",
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
Issuer: "test",
}}
token := jwt.NewWithClaims(jwt.SigningMethodRS256,
claims,
)
if err != nil {
log.Fatalf("Unable to initialize signer: %v", err)
}
token.Header["kid"] = keyID
tokenString, err := token.SignedString(r)
if err != nil {
log.Fatalf("Error signing %v", err)
}
fmt.Printf("TOKEN: %s\n", tokenString)
/// **** verify with JWK
jwtSet, err = jwk.FetchHTTP(jwksURL)
if err != nil {
log.Fatal("Unable to load JWK Set: ", err)
}
//t, err := jwt.Parse(tokenString, getKey)
t, err := jwt.ParseWithClaims(tokenString, &gcpIdentityDoc{}, getKey)
if err != nil {
log.Fatalf(" Error parsing JWT %v", err)
}
if claims, ok := t.Claims.(*gcpIdentityDoc); ok && t.Valid {
log.Printf(" OIDC doc has Audience [%s] Issuer [%s] and SubjectEmail [%s]", claims.Audience, claims.StandardClaims.Issuer, claims.Email)
}
}
func getKey(token *jwt.Token) (interface{}, error) {
keyID, ok := token.Header["kid"]
if !ok {
return nil, errors.New("expecting JWT header to have string kid")
}
if key := jwtSet.LookupKeyID(keyID.(string)); len(key) == 1 {
log.Printf(" Found OIDC KeyID " + keyID.(string))
return key[0].Materialize()
}
return nil, errors.New("unable to find key")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment