jwt.go

 1package cmd
 2
 3import (
 4	"fmt"
 5	"time"
 6
 7	"github.com/charmbracelet/soft-serve/pkg/config"
 8	"github.com/charmbracelet/soft-serve/pkg/jwk"
 9	"github.com/charmbracelet/soft-serve/pkg/proto"
10	"github.com/golang-jwt/jwt/v5"
11	"github.com/spf13/cobra"
12)
13
14// JWTCommand returns a command that generates a JSON Web Token.
15func JWTCommand() *cobra.Command {
16	cmd := &cobra.Command{
17		Use:   "jwt [repository1 repository2...]",
18		Short: "Generate a JSON Web Token",
19		Args:  cobra.MinimumNArgs(0),
20		RunE: func(cmd *cobra.Command, args []string) error {
21			ctx := cmd.Context()
22			cfg := config.FromContext(ctx)
23			kp, err := jwk.NewPair(cfg)
24			if err != nil {
25				return err //nolint:wrapcheck
26			}
27
28			user := proto.UserFromContext(ctx)
29			if user == nil {
30				return proto.ErrUserNotFound
31			}
32
33			now := time.Now()
34			expiresAt := now.Add(time.Hour)
35			claims := jwt.RegisteredClaims{
36				Subject:   fmt.Sprintf("%s#%d", user.Username(), user.ID()),
37				ExpiresAt: jwt.NewNumericDate(expiresAt), // expire in an hour
38				NotBefore: jwt.NewNumericDate(now),
39				IssuedAt:  jwt.NewNumericDate(now),
40				Issuer:    cfg.HTTP.PublicURL,
41				Audience:  args,
42			}
43
44			token := jwt.NewWithClaims(jwk.SigningMethod, claims)
45			token.Header["kid"] = kp.JWK().KeyID
46			j, err := token.SignedString(kp.PrivateKey())
47			if err != nil {
48				return err //nolint:wrapcheck
49			}
50
51			cmd.Println(j)
52			return nil
53		},
54	}
55
56	return cmd
57}