Rename the module, proto service, and all identifiers from simple_bank/ SimpleBank to api_tmpl/ApiTmpl, and regenerate the gRPC/gateway/swagger/ mock code accordingly. - Scrub real secrets (SMTP password, auth token secret) from api.env/ api_test.env, untrack them, and add api.env.example/api_test.env.example - Remove committed build artifacts (tmp/main, tmp/build-errors.log, dbml-error.log) and gitignore them going forward - Fix Dockerfile paths (build target, migrations copy) that referenced a stale project layout - Rewrite README to match the actual cmd/ + internal/ structure and add a "using this as a template" section
98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"aidanwoods.dev/go-paseto"
|
|
"github.com/FernandoJVideira/api_tmpl/internal/config"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type PasetoMaker struct {
|
|
config config.Config
|
|
symmetricKey paseto.V4SymmetricKey
|
|
implicit []byte
|
|
}
|
|
|
|
func NewPasetoMaker(config config.Config) (Maker, error) {
|
|
maker := &PasetoMaker{
|
|
config: config,
|
|
symmetricKey: paseto.NewV4SymmetricKey(),
|
|
implicit: []byte("implicit"),
|
|
}
|
|
return maker, nil
|
|
}
|
|
|
|
func (maker *PasetoMaker) CreateToken(username string, role string, duration time.Duration) (string, *Payload, error) {
|
|
payload, err := NewPayload(username, role, duration)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
token := paseto.NewToken()
|
|
token.SetIssuedAt(payload.IssuedAt)
|
|
token.SetExpiration(payload.ExpiredAt)
|
|
token.SetString("role", payload.Role)
|
|
token.SetAudience(maker.config.TokenAUD)
|
|
token.SetIssuer(maker.config.TokenISS)
|
|
token.SetSubject(payload.Username)
|
|
token.SetJti(payload.ID.String())
|
|
|
|
signedToken := token.V4Encrypt(maker.symmetricKey, maker.implicit)
|
|
|
|
return signedToken, payload, nil
|
|
}
|
|
|
|
func (maker *PasetoMaker) VerifyToken(token string) (*Payload, error) {
|
|
parser := paseto.NewParser()
|
|
parser.AddRule(paseto.NotExpired())
|
|
|
|
parsedToken, err := parser.ParseV4Local(maker.symmetricKey, token, maker.implicit)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "token has expired") {
|
|
return nil, ErrExpiredToken
|
|
}
|
|
return nil, ErrInvalidToken
|
|
}
|
|
|
|
payload, err := parseClaims(parsedToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return payload, nil
|
|
}
|
|
|
|
func parseClaims(t *paseto.Token) (*Payload, error) {
|
|
id, err := t.GetJti()
|
|
if err != nil {
|
|
return nil, ErrInvalidToken
|
|
}
|
|
username, err := t.GetSubject()
|
|
if err != nil {
|
|
return nil, ErrInvalidToken
|
|
}
|
|
role, err := t.GetString("role")
|
|
if err != nil {
|
|
return nil, ErrInvalidToken
|
|
}
|
|
issuedAt, err := t.GetIssuedAt()
|
|
if err != nil {
|
|
return nil, ErrInvalidToken
|
|
}
|
|
expiredAt, err := t.GetExpiration()
|
|
if err != nil {
|
|
return nil, ErrInvalidToken
|
|
}
|
|
|
|
payload := &Payload{
|
|
ID: uuid.MustParse(id),
|
|
Username: username,
|
|
Role: role,
|
|
IssuedAt: issuedAt,
|
|
ExpiredAt: expiredAt,
|
|
}
|
|
return payload, nil
|
|
}
|