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