github.com/simpleiot/simpleiot@v0.18.3/api/key.go (about) 1 package api 2 3 import ( 4 "net/http" 5 "strings" 6 "time" 7 8 "github.com/golang-jwt/jwt/v4" 9 ) 10 11 // Authorizer defines a mechanism needed to authorize stuff 12 type Authorizer interface { 13 NewToken(id string) (string, error) 14 Valid(req *http.Request) (bool, string) 15 } 16 17 // AlwaysValid is used to disable authentication 18 type AlwaysValid struct{} 19 20 // NewToken stub 21 func (AlwaysValid) NewToken(_ string) (string, error) { return "valid", nil } 22 23 // Valid stub 24 func (AlwaysValid) Valid(*http.Request) (bool, string) { 25 return true, "" 26 } 27 28 // Key provides a key for signing authentication tokens. 29 type Key struct { 30 bytes []byte 31 } 32 33 // NewKey returns a new Key of the given size. 34 func NewKey(bytes []byte) (key Key, err error) { 35 key.bytes = bytes 36 return 37 } 38 39 // NewToken returns a new authentication token signed by the Key. 40 func (k Key) NewToken(userID string) (string, error) { 41 // FIXME Id is probably not the proper place to put the userid 42 // but works for now 43 claims := jwt.StandardClaims{ 44 ExpiresAt: time.Now().Add(168 * time.Hour).Unix(), 45 Issuer: "simpleiot", 46 Id: userID, 47 } 48 return jwt.NewWithClaims(jwt.SigningMethodHS256, claims). 49 SignedString(k.bytes) 50 } 51 52 // ValidToken returns whether the given string 53 // is an authentication token signed by the Key. 54 func (k Key) ValidToken(str string) (bool, string) { 55 token, err := jwt.Parse(str, k.keyFunc) 56 if err != nil { 57 return false, "" 58 } 59 claims, ok := token.Claims.(jwt.MapClaims) 60 if !ok { 61 return false, "" 62 } 63 userID, ok := claims["jti"].(string) 64 if !ok { 65 return false, "" 66 } 67 return (err == nil && 68 token.Method.Alg() == "HS256" && 69 token.Valid), userID 70 } 71 72 // Valid returns whether the given request 73 // bears an authorization token signed by the Key. 74 func (k Key) Valid(req *http.Request) (bool, string) { 75 fields := strings.Fields(req.Header.Get("Authorization")) 76 if len(fields) < 2 { 77 return false, "" 78 } 79 if fields[0] != "Bearer" { 80 return false, "" 81 } 82 83 valid, userID := k.ValidToken(fields[1]) 84 return valid, userID 85 } 86 87 func (k Key) keyFunc(*jwt.Token) (interface{}, error) { 88 return k.bytes, nil 89 }