firebaseJwtValidator

package module
v0.0.0-...-04a13f4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2017 License: MIT Imports: 13 Imported by: 0

README

Build Status codecov

firebaseJwtValidator

This is a GO package for validating JWT based identity tokens for Googles Firebase authentication.
There are many general purpose JWT validators out there that could be used, but this package is a very specific JWT validator for a Firebase project.

The package validates a token as to the rules described by the Firebase documentation as they where on July 2th 2017 (Firebase JWT doc), specifically it makes the following checks.

JWT Header
  • alg = RS256
  • kid exists
JWT Claims
  • exp = now or in the future
  • iat = now or in the past. Allows for IAT to be up to ten seconds in the future to avoid problems that arose when the validating server was not completely in sync with the JWT issuing server.
  • aud = a supplied firebase project id
  • iss = https://securetoken.google.com/<projectId> where <projectID> is the same value as used in aud
  • sub exists
JWT Signature

Fetches the public key from Googles key server and validates the JWT signature against the header and claims. The package will cache the response from Googles server in accordance with the response cache-control max-age setting.

Both header and claims sections can have more attributes than the ones listed and they will not be taken into account in the validation.

Usuage

While it is possible to subtitues your own validators for the header, claims or signature parts of the JWT by implementing one of the *Validator interfaces, the package also supplies default implementations that performs the above rules. Below is a small example of validating a token.

package main

import (
  "fmt"
  fjv "github.com/Morras/firebaseJwtValidator"
  "os"
)

func main() {
  // Use the first command line argument as the token to validate
  token := os.Args[1]
  // Creates the validator with your project ID
  validator := fjv.NewDefaultTokenValidator("Your-Project-ID")
  // Validates a token against the Firebase JWT rules.
  valid, err := validator.Validate(token)

  fmt.Printf("Token is valid: %v\n", valid)
  fmt.Printf("Validation gave the error: %v\n", err)
}

Testing

I have set up a functional test in a cron job on Travis-ci that logs in a user in a test project I have set up only for this project. This allows the test to get a fresh token and try an validate that.
Other than that all classes are unit tested in more or less of a test first fashion.

Testing is done with the Ginkgo testing framework using Gomega matchers, but outside those two packages, everything is made using GOs standard library.

Feedback

I would appreciate any feedback you might have on this code, or just a ping if you are using it. I have only messed around with GO on my own, so I am probably still using a Java style where there would be more idomatic ways of doing things in GO.

Documentation

Index

Constants

View Source
const KeyServerURL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"

KeyServerURL points to the location that the CachedKeyFetcher will retrieve its keys from.

Variables

View Source
var ErrClaimsValidationFailed = errors.New("Claims validation failed")

ErrClaimsValidationFailed indicates that something went wrong when validating the JWT claims. It should be possible to find specific information about the error in the logs.

View Source
var ErrHeaderValidationFailed = errors.New("Header validation failed")

ErrHeaderValidationFailed indicates that something went wrong when validating the JWT header. It should be possible to find specific information about the error in the logs.

View Source
var ErrKeyServerConnectionFailed = errors.New("Unable to connect to the key server")

ErrKeyServerConnectionFailed indicates that something went wrong when getting the data from Googles key server. It should be possible to find specific information about the error in the logs.

View Source
var ErrMalformedToken = errors.New("Token is malformed")

ErrMalformedToken indicates that the JWT is malformed and could not be parsed. It should be possible to find specific information about the error in the logs.

View Source
var ErrNoSuchKey = errors.New("No such key")

ErrNoSuchKey indicates that the public key to verify the signature was not present in the response from Google key server. It should be possible to find specific information about the error in the logs.

View Source
var ErrSignatureValidationFailed = errors.New("Signature validation failed")

ErrSignatureValidationFailed indicates that something went wrong when validating the JWT signature. It should be possible to find specific information about the error in the logs.

Functions

func DecodeRawClaims

func DecodeRawClaims(raw string) (bool, claims)

DecodeRawClaims decode Base64 encoded claims, but does no validation outside making sure it is valid Base64 and json.

Types

type CachedKeyFetcher

type CachedKeyFetcher struct {
	// contains filtered or unexported fields
}

CachedKeyFetcher is an implementation of KeyFetcher

func NewCachedKeyFetcher

func NewCachedKeyFetcher(httpClient HTTPClient) *CachedKeyFetcher

NewCachedKeyFetcher creates a new CachedKeyFetcher using httpClient to get data from the key server.

func (*CachedKeyFetcher) FetchKey

func (kf *CachedKeyFetcher) FetchKey(kid string) (*rsa.PublicKey, error)

FetchKey returns a PublicKey from its local cache if the cache is not expired. If the key does not exist and the cache is not expired, it returns nil and an error. The cache expiration is based on the cache-control: max-age as described in the Firebase documentation.

type ClaimsValidator

type ClaimsValidator interface {
	// Validate determines whether the JWT claims are valid for a Firebase issued JWT when the projects id is projectID.
	// The claims are supplied in the base64 encoded value that is read directly from the JWT.
	Validate(claims string, projectID string) bool
}

A ClaimsValidator validates the claims part of a JWT token.

type DefaultClaimsValidator

type DefaultClaimsValidator struct {
	// contains filtered or unexported fields
}

DefaultClaimsValidator implements the logic set out in the Firebase documentation to validate the JWT claims.

func NewDefaultClaimsValidator

func NewDefaultClaimsValidator() *DefaultClaimsValidator

func (*DefaultClaimsValidator) Validate

func (hv *DefaultClaimsValidator) Validate(claims string, projectID string) bool

Validate returns true if the claims provided in the raw base64 encoded value from the JWT lives up to the requirements from Firebases documentation for a project with projectID as id.

The rules are:

  • Sub must exist and be non empty
  • iat must not be after now
  • exp must not be before now
  • aud must be the same as projectID
  • iss must be https://securetoken.google.com/<projectID>

type DefaultHeaderValidator

type DefaultHeaderValidator struct {
}

DefaultHeaderValidator implements the logic set out in the Firebase documentation to validate the JWT header.

func (*DefaultHeaderValidator) Validate

func (hv *DefaultHeaderValidator) Validate(raw string) bool

Validate determines whether the JWT header are valid for a Firebase issued JWT. The Header are supplied in the base64 encoded value that is read directly from the JWT.

The rules for header validation is that

  • alg must be RS256
  • kid must exist

type DefaultSignatureValidator

type DefaultSignatureValidator struct {
	// contains filtered or unexported fields
}

The DefaultSignatureValidator uses a KeyFetcher to get the public key it tries to verify the signature with.

func NewDefaultSignatureValidator

func NewDefaultSignatureValidator(kf KeyFetcher) *DefaultSignatureValidator

NewDefaultSignatureValidator creates a DefaultSignatureValidator that uses the supplie KeyFetcher to get the public key to verify the signature.

func (*DefaultSignatureValidator) Validate

func (sv *DefaultSignatureValidator) Validate(signature string, kid string, message string) bool

Validate determines if the signature supplied in its JWT base64 segment matches the signature of message using the public key with the id of kid.

type HTTPClient

type HTTPClient interface {
	Get(string) (*http.Response, error)
}

HTTPClient is used to call an URL with a get method and read the response.

type HeaderValidator

type HeaderValidator interface {
	// Validate determines whether the JWT header are valid for a Firebase issued JWT.
	// The Header are supplied in the base64 encoded value that is read directly from the JWT.
	Validate(header string) bool
}

A HeaderValidator validates the claims part of a JWT token.

type KeyFetcher

type KeyFetcher interface {
	FetchKey(kid string) (*rsa.PublicKey, error)
}

KeyFetcher interface implementations should get the public key needed to validate a signature based on the keys ID.

type SignatureValidator

type SignatureValidator interface {
	Validate(signature string, kid string, message string) bool
}

A SignatureValidator validates the sugnature part of a JWT token.

type TokenValidator

type TokenValidator interface {
	Validate(token string) (bool, error)
}

func NewDefaultTokenValidator

func NewDefaultTokenValidator(projectID string) TokenValidator

NewDefaultTokenValidator is the default token validator that validates using the DefaultHeaderValidator, DefaultClaimsValidator and DefaultSignatureValidator to validate a token against the rules set out by the Firebase projects documentation.

func NewTokenValidator

func NewTokenValidator(projectID string, headerValidator HeaderValidator, claimsValidator ClaimsValidator, signatureValidator SignatureValidator) TokenValidator

NewTokenValidator allows you to customize the TokenValidator by substituting validators for the individual JWT segments. See the validator interfaces for implementation details on the specific validators.

type TokenValidatorImpl

type TokenValidatorImpl struct {
	// contains filtered or unexported fields
}

TokenValidator is a struct to hold validators used to validate a JWT against the rules set out by the Firebase project.

func (*TokenValidatorImpl) Validate

func (tv *TokenValidatorImpl) Validate(token string) (bool, error)

Validate a jwt token against the rules set out in the TokenValidators three validators. Return result of the validation and an error telling which part of the validation went wrong if the result is false.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL