mirror of
https://forgejo.merr.is/annika/isl-api.git
synced 2025-12-11 14:28:48 -05:00
This can verify a JWT using the JWKS fetched from an OAuth's endpoint.
This commit is contained in:
parent
d4b2d5fefb
commit
ac18b94a86
6 changed files with 173 additions and 10 deletions
64
main.go
64
main.go
|
|
@ -4,25 +4,48 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"forgejo.merr.is/annika/isl-api/Controllers"
|
||||
routes "forgejo.merr.is/annika/isl-api/Routes"
|
||||
"forgejo.merr.is/annika/isl-api/Routes"
|
||||
"forgejo.merr.is/annika/isl-api/Services"
|
||||
"forgejo.merr.is/annika/isl-api/sql/powerItem"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/go-chi/httplog/v2"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/lestrrat-go/jwx/v2/jwk"
|
||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||
"github.com/lmittmann/tint"
|
||||
"github.com/moosetheory/jwtauth/v5"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var conf *EnvConfigs
|
||||
var logger *slog.Logger
|
||||
|
||||
func init() {
|
||||
w := os.Stderr
|
||||
logger = slog.New(
|
||||
tint.NewHandler(w, &tint.Options{
|
||||
TimeFormat: time.RFC3339Nano,
|
||||
}),
|
||||
)
|
||||
logger.Info("Initializing isl-api")
|
||||
setupConfig()
|
||||
logger = slog.New(
|
||||
tint.NewHandler(w, &tint.Options{
|
||||
Level: conf.GetLogLevel(),
|
||||
TimeFormat: time.RFC3339Nano,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func main() {
|
||||
logger.Info("Starting isl-api")
|
||||
deps := dependencies{}
|
||||
deps.initializeDependencies()
|
||||
|
||||
|
|
@ -32,6 +55,7 @@ func main() {
|
|||
}
|
||||
|
||||
func setupConfig() {
|
||||
logger.Info("Loading config")
|
||||
viper.AddConfigPath(".")
|
||||
viper.SetConfigName(".env")
|
||||
viper.SetConfigType("env")
|
||||
|
|
@ -40,27 +64,49 @@ func setupConfig() {
|
|||
viper.AutomaticEnv()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
fmt.Printf("Error reading env file: %v\n", err)
|
||||
logger.Error("Error reading env file, exiting", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := viper.Unmarshal(&conf); err != nil {
|
||||
log.Fatal(err)
|
||||
logger.Error("Unable to unmarshal configuration, exiting", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
logger.Info("Finished loading config")
|
||||
}
|
||||
|
||||
type dependencies struct {
|
||||
router *chi.Mux
|
||||
postgresConnection *pgxpool.Pool
|
||||
context context.Context
|
||||
jwkContext context.Context
|
||||
powerItemQuerier *powerItem.DBQuerier
|
||||
powerItemService *Services.PowerItemService
|
||||
powerItemController *Controllers.PowerItemController
|
||||
jwkCache *jwk.Cache
|
||||
}
|
||||
|
||||
func (d *dependencies) initializeDependencies() error {
|
||||
logger.Info("Initializing dependencies")
|
||||
var err error
|
||||
d.jwkContext = context.Background()
|
||||
d.jwkCache = jwk.NewCache(d.jwkContext)
|
||||
d.jwkCache.Register(conf.JWKSURI, jwk.WithMinRefreshInterval(15*time.Minute))
|
||||
_, err = d.jwkCache.Refresh(d.jwkContext, conf.JWKSURI)
|
||||
if err != nil {
|
||||
logger.Error("Error setting up JWK cache", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
d.router = chi.NewRouter()
|
||||
|
||||
httpLogger := httplog.NewLogger("isl-api", httplog.Options{
|
||||
Concise: true,
|
||||
RequestHeaders: true,
|
||||
})
|
||||
httpLogger.Logger = logger
|
||||
d.router.Use(httplog.RequestLogger(httpLogger))
|
||||
|
||||
d.router.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
|
|
@ -69,11 +115,21 @@ func (d *dependencies) initializeDependencies() error {
|
|||
d.context = context.Background()
|
||||
d.postgresConnection, err = pgxpool.Connect(d.context, conf.ConnectionString)
|
||||
if err != nil {
|
||||
logger.Error("Error setting up database connection", "error", err)
|
||||
return err
|
||||
}
|
||||
d.powerItemQuerier = powerItem.NewQuerier(d.postgresConnection)
|
||||
d.powerItemService = Services.NewPowerItemService(d.powerItemQuerier)
|
||||
d.powerItemController = Controllers.NewPowerItemController(d.powerItemService)
|
||||
d.router.Mount("/powerItems", routes.SetupPowerItemRoutes(*d.powerItemController))
|
||||
|
||||
jwkSet, err := d.jwkCache.Get(d.jwkContext, conf.JWKSURI)
|
||||
if err != nil {
|
||||
logger.Error("Error getting JWKS", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
tokenAuth := jwtauth.New("HS256", nil, nil, jwkSet, jwt.WithAcceptableSkew(30*time.Second))
|
||||
d.router.Mount("/powerItems", Routes.SetupPowerItemRoutes(*d.powerItemController, tokenAuth))
|
||||
logger.Info("Finished initializing dependencies")
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue