token.go raw

   1  package jwt
   2  
   3  import (
   4  	"encoding/base64"
   5  	"encoding/json"
   6  	"errors"
   7  	"fmt"
   8  	"strings"
   9  	"time"
  10  )
  11  
  12  // Token is the jwt that will be used by the client in the Authorization header
  13  // to send in every request to the api server, every request except for the auth request
  14  // which is used to request a new token.
  15  //
  16  // For more information see: https://jwt.io/
  17  type Token struct {
  18  	ExpiryDate int64
  19  	RawToken   string
  20  }
  21  
  22  // Define a hard expiration skew in seconds,
  23  // so we will retrieve a new token way before the moment of expiration
  24  const expirationSkew = 30
  25  
  26  // Expired returns true when the token expiry date is reached
  27  func (t *Token) Expired() bool {
  28  	return time.Now().Unix()+expirationSkew > t.ExpiryDate
  29  }
  30  
  31  // GetAuthenticationHeaderValue returns the authentication header value value
  32  // including the Bearer prefix
  33  func (t *Token) GetAuthenticationHeaderValue() string {
  34  	return fmt.Sprintf("Bearer %s", t.RawToken)
  35  }
  36  
  37  // String returns the string representation of the Token struct
  38  func (t *Token) String() string {
  39  	return t.RawToken
  40  }
  41  
  42  // tokenPayload is used to unpack the payload from the jwt
  43  type tokenPayload struct {
  44  	// This ExpirationTime is a 64 bit epoch that will be put into the token struct
  45  	// that will later be used to validate if the token is expired or not
  46  	// once expired we need to request a new token
  47  	ExpirationTime int64 `json:"exp"`
  48  }
  49  
  50  // New expects a raw token as string.
  51  // It will try to decode it and return an error on error.
  52  // Once decoded it will retrieve the expiry date and
  53  // return a Token struct with the RawToken and ExpiryDate set.
  54  func New(token string) (Token, error) {
  55  	if len(token) == 0 {
  56  		return Token{}, errors.New("no token given, a token should be set")
  57  	}
  58  
  59  	tokenParts := strings.Split(token, ".")
  60  	if len(tokenParts) != 3 {
  61  		return Token{}, fmt.Errorf("invalid token '%s' given, token should exist at least of 3 parts", token)
  62  	}
  63  
  64  	jsonBody, err := base64.RawURLEncoding.DecodeString(tokenParts[1])
  65  	if err != nil {
  66  		return Token{}, errors.New("could not decode token, invalid base64")
  67  	}
  68  
  69  	var tokenRequest tokenPayload
  70  	err = json.Unmarshal(jsonBody, &tokenRequest)
  71  	if err != nil {
  72  		return Token{}, errors.New("could not read token body, invalid json")
  73  	}
  74  
  75  	return Token{
  76  		RawToken:   token,
  77  		ExpiryDate: tokenRequest.ExpirationTime,
  78  	}, nil
  79  }
  80