Implemented API endpoint to sign arbitrary data

This commit is contained in:
ErickSkrauch
2024-03-05 13:07:54 +01:00
parent f5bc474b4d
commit 436ff7c294
20 changed files with 748 additions and 255 deletions

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net/http"
"slices"
"strings"
"time"
@@ -15,14 +16,23 @@ import (
var now = time.Now
var signingMethod = jwt.SigningMethodHS256
const scopesClaim = "scopes"
type Scope string
const (
ProfileScope Scope = "profiles"
ProfilesScope Scope = "profiles"
SignScope Scope = "sign"
)
var validScopes = []Scope{
ProfilesScope,
SignScope,
}
type claims struct {
jwt.RegisteredClaims
Scopes []Scope `json:"scopes"`
}
func NewJwt(key []byte) *Jwt {
return &Jwt{
Key: key,
@@ -38,11 +48,20 @@ func (t *Jwt) NewToken(scopes ...Scope) (string, error) {
return "", errors.New("you must specify at least one scope")
}
token := jwt.NewWithClaims(signingMethod, jwt.MapClaims{
"iss": "chrly",
"iat": now().Unix(),
scopesClaim: scopes,
})
for _, scope := range scopes {
if !slices.Contains(validScopes, scope) {
return "", fmt.Errorf("unknown scope %s", scope)
}
}
token := jwt.New(signingMethod)
token.Claims = &claims{
jwt.RegisteredClaims{
Issuer: "chrly",
IssuedAt: jwt.NewNumericDate(now()),
},
scopes,
}
token.Header["v"] = version.MajorVersion
return token.SignedString(t.Key)
@@ -52,7 +71,7 @@ func (t *Jwt) NewToken(scopes ...Scope) (string, error) {
var MissingAuthenticationError = errors.New("authentication value not provided")
var InvalidTokenError = errors.New("passed authentication value is invalid")
func (t *Jwt) Authenticate(req *http.Request) error {
func (t *Jwt) Authenticate(req *http.Request, scope Scope) error {
bearerToken := req.Header.Get("Authorization")
if bearerToken == "" {
return MissingAuthenticationError
@@ -62,8 +81,8 @@ func (t *Jwt) Authenticate(req *http.Request) error {
return InvalidTokenError
}
tokenStr := bearerToken[7:]
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
tokenStr := bearerToken[7:] // trim "bearer " part
token, err := jwt.ParseWithClaims(tokenStr, &claims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
@@ -78,5 +97,10 @@ func (t *Jwt) Authenticate(req *http.Request) error {
return errors.Join(InvalidTokenError, errors.New("missing v header"))
}
claims := token.Claims.(*claims)
if !slices.Contains(claims.Scopes, scope) {
return errors.New("the token doesn't have the scope to perform the action")
}
return nil
}