Created
November 6, 2015 22:26
-
-
Save kentquirk/2184391c2216c99bc1a5 to your computer and use it in GitHub Desktop.
Go demonstration of decoding jwt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"crypto" | |
"crypto/rsa" | |
"crypto/sha256" | |
"encoding/base64" | |
"encoding/binary" | |
"encoding/json" | |
"errors" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"math/big" | |
"net/http" | |
"strings" | |
"github.com/dgrijalva/jwt-go" | |
) | |
func (u *UserServer) unpackToken(token, secret string) (string, error) { | |
jwtToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { return []byte(secret), nil }) | |
if err != nil { | |
fmt.Println(err) | |
return "", err | |
} | |
fmt.Println(jwtToken) | |
return "", nil | |
} | |
func decode(auth_token string) error { | |
w := strings.Split(auth_token, ".") | |
if len(w) < 3 { | |
return errors.New("invalid token") | |
} | |
jwtHdr, jwtBody, jwtSig := w[0], w[1], w[2] | |
if m := len(jwtHdr) % 4; m != 0 { | |
jwtHdr += strings.Repeat("=", 4-m) | |
} | |
if m := len(jwtSig) % 4; m != 0 { | |
jwtSig += strings.Repeat("=", 4-m) | |
} | |
headerOauth, err := base64.URLEncoding.DecodeString(jwtHdr) | |
fmt.Println(string(headerOauth)) | |
bodyOauth, err := base64.URLEncoding.DecodeString(jwtBody) | |
fmt.Println(string(bodyOauth)) | |
res, err := http.Get("https://www.googleapis.com/oauth2/v2/certs") | |
if err != nil { | |
fmt.Println(err) | |
return err | |
} | |
certs, err := ioutil.ReadAll(res.Body) | |
res.Body.Close() | |
if err != nil { | |
fmt.Println(err) | |
return err | |
} | |
//extract kid from token header | |
var header interface{} | |
err = json.Unmarshal([]byte(string(headerOauth)), &header) | |
token_kid := header.(map[string]interface{})["kid"] | |
fmt.Println("By 1") | |
//get modulus and exponent from the cert | |
var goCertificate interface{} | |
err = json.Unmarshal(certs, &goCertificate) | |
//k := goCertificate.(map[string]interface{})[token_kid.(string)] | |
k := goCertificate.(map[string]interface{})["keys"] | |
///*mod & exp part | |
j := k.([]interface{}) | |
x := j[0] | |
if j[0].(map[string]interface{})["kid"] == token_kid { | |
x = j[0] | |
} else { | |
if j[1].(map[string]interface{})["kid"] == token_kid { | |
x = j[1] | |
} else { | |
err = errors.New("Token is not valid, kid from token and certificate don't match") | |
return err | |
} | |
} | |
h := x.(map[string]interface{})["n"] | |
g := x.(map[string]interface{})["e"] | |
//build the google pub key | |
nStr := h.(string) | |
decN, err := base64.URLEncoding.DecodeString(nStr) | |
if err != nil { | |
fmt.Println(err) | |
return err | |
} | |
n := big.NewInt(0) | |
n.SetBytes(decN) | |
eStr := g.(string) | |
decE, err := base64.URLEncoding.DecodeString(eStr) | |
if err != nil { | |
fmt.Println(err) | |
return err | |
} | |
var eBytes []byte | |
if len(decE) < 8 { | |
eBytes = make([]byte, 8-len(decE), 8) | |
eBytes = append(eBytes, decE...) | |
} else { | |
eBytes = decE | |
} | |
eReader := bytes.NewReader(eBytes) | |
var e uint64 | |
err = binary.Read(eReader, binary.BigEndian, &e) | |
if err != nil { | |
log.Println(err) | |
return err | |
} | |
pKey := rsa.PublicKey{N: n, E: int(e)} | |
//inblockOauth := base64.URLEncoding.DecodeString(w[1]) | |
toHash := w[0] + "." + w[1] | |
digestOauth, err := base64.URLEncoding.DecodeString(jwtSig) | |
hasherOauth := sha256.New() | |
hasherOauth.Write([]byte(toHash)) | |
// verification of the signature | |
err = rsa.VerifyPKCS1v15(&pKey, crypto.SHA256, hasherOauth.Sum(nil), digestOauth) | |
if err != nil { | |
fmt.Printf("Error verifying key %s", err.Error()) | |
return err | |
} | |
fmt.Printf("OK!") | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment