Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Verify the JSON Web Token obtained from Firebase Authentication. But now, Go SDK is released by firebase organization.
package jwt
import (
"crypto/rsa"
"errors"
"encoding/json"
"io/ioutil"
"net/http"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/dgrijalva/jwt-go"
)
// CertsAPIEndpoint is endpoint of getting Public Key.
var CertsAPIEndpoint = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
// GetCertificate is useful for testing.
var GetCertificate = getCertificate
func getCertificates() (certs map[string]string, err error) {
res, err := http.Get(CertsAPIEndpoint)
if err != nil {
return
}
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
return
}
json.Unmarshal(data, &certs)
return
}
// GetCertificate returns certificate.
func getCertificate(kid string) (cert []byte, err error) {
certs, err := getCertificates()
if err != nil {
return
}
certString := certs[kid]
cert = []byte(certString)
err = nil
return
}
// VerifyJWT to verify the token header, payload and signature.
var VerifyJWT = verifyJWT
// GetCertificateFromToken returns cert from token.
func GetCertificateFromToken(token *jwt.Token) ([]byte, error) {
// Get kid
kid, ok := token.Header["kid"]
if !ok {
return []byte{}, errors.New("kid not found")
}
kidString, ok := kid.(string)
if !ok {
return []byte{}, errors.New("kid cast error to string")
}
return GetCertificate(kidString)
}
// Verify the token payload.
func verifyPayload(t *jwt.Token, projectID string) (ok bool, uid string) {
claims, ok := t.Claims.(jwt.MapClaims)
if !ok {
return
}
// Verify User
claimsAud, ok := claims["aud"].(string)
if claimsAud != projectID || !ok {
return
}
// Verify issued at
iss := "https://securetoken.google.com/" + projectID
claimsIss, ok := claims["iss"].(string)
if claimsIss != iss || !ok {
return
}
// sub is uid of user.
uid, ok = claims["sub"].(string)
if !ok {
return
}
return
}
func readPublicKey(cert []byte) (*rsa.PublicKey, error) {
publicKeyBlock, _ := pem.Decode(cert)
if publicKeyBlock == nil {
return nil, errors.New("invalid public key data")
}
if publicKeyBlock.Type != "CERTIFICATE" {
return nil, fmt.Errorf("invalid public key type: %s", publicKeyBlock.Type)
}
c, err := x509.ParseCertificate(publicKeyBlock.Bytes)
if err != nil {
return nil, err
}
publicKey, ok := c.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not RSA public key")
}
return publicKey, nil
}
func verifyJWT(t, projectID string) (uid string, ok bool) {
parsed, _ := jwt.Parse(t, func(t *jwt.Token) (interface{}, error) {
cert, err := GetCertificateFromToken(t)
if err != nil {
return "", err
}
publicKey, err := readPublicKey(cert)
if err != nil {
return "", err
}
return publicKey, nil
})
ok = parsed.Valid
if !ok {
return
}
// Verify header.
if parsed.Header["alg"] != "RS256" {
ok = false
return
}
// Verify payload.
ok, uid = verifyPayload(parsed, projectID)
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment