-
Notifications
You must be signed in to change notification settings - Fork 0
Goten with Gin
This page is short by design: Goten exposes a plain http.Handler, and Gin wraps any http.Handler with gin.WrapH. No adapter package needed.
If you have not yet, walk through the Quick Start first to get Goten configured, the database migrated, and auth working with net/http. Then come back here to mount it under Gin.
On top of the Quick Start dependencies:
go get github.com/gin-gonic/ginimport (
goten "github.com/dnahilman/goten"
"github.com/gin-gonic/gin"
)
r := gin.Default()
r.Any("/api/auth/*action", gin.WrapH(auth.Handler()))How this works: Goten internally registers exact routes like POST /api/auth/sign-up/email, GET /api/auth/get-session, and so on inside its own http.ServeMux. Gin's *action is a catch-all that forwards the full request — Goten then matches it against its registered routes. The wildcard path segment is captured by Gin but ignored; Goten reads r.URL.Path directly.
Two equivalent forms. Pick whichever reads better in your code.
r.GET("/api/me", gin.WrapH(auth.RequireAuth(http.HandlerFunc(meHandler))))
func meHandler(w http.ResponseWriter, r *http.Request) {
user, _ := goten.UserFromContext(r.Context())
_ = json.NewEncoder(w).Encode(user)
}Quick, but you give up the Gin handler signature.
// RequireAuth wraps Goten's auth middleware as a Gin middleware.
// It propagates the user+session that Goten injects into the request
// context back into c.Request, so downstream Gin handlers can read them.
func RequireAuth(auth *goten.Auth) gin.HandlerFunc {
return func(c *gin.Context) {
allow := false
next := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
allow = true
c.Request = r // carry the enriched context into Gin
})
auth.RequireAuth(next).ServeHTTP(c.Writer, c.Request)
if !allow {
c.Abort()
return
}
c.Next()
}
}Then your route reads naturally:
r.GET("/api/me", RequireAuth(auth), func(c *gin.Context) {
user, _ := goten.UserFromContext(c.Request.Context())
c.JSON(http.StatusOK, user)
})Both helpers take a context.Context and return (*Model, bool) — not error. The bool is false when no user/session is in context (e.g. you forgot the middleware).
user, ok := goten.UserFromContext(c.Request.Context())
if !ok {
// should not happen behind RequireAuth
c.AbortWithStatus(http.StatusUnauthorized)
return
}
session, _ := goten.SessionFromContext(c.Request.Context())
_ = session.ExpiresAtpackage main
import (
"log"
"net/http"
goten "github.com/dnahilman/goten"
gormadapter "github.com/dnahilman/goten/adapters/gorm"
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func RequireAuth(auth *goten.Auth) gin.HandlerFunc {
return func(c *gin.Context) {
allow := false
next := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
allow = true
c.Request = r
})
auth.RequireAuth(next).ServeHTTP(c.Writer, c.Request)
if !allow {
c.Abort()
return
}
c.Next()
}
}
func main() {
db, err := gorm.Open(
postgres.Open("postgres://goten:goten@localhost:5432/goten?sslmode=disable"),
&gorm.Config{},
)
if err != nil {
log.Fatal(err)
}
auth, err := goten.New(goten.Config{
BaseURL: "http://localhost:8080",
Secret: "your-32-byte-secret-key-here!!!!",
Adapter: gormadapter.New(db),
})
if err != nil {
log.Fatal(err)
}
r := gin.Default()
// Goten's auth endpoints under /api/auth/*
r.Any("/api/auth/*action", gin.WrapH(auth.Handler()))
// Public route
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
// Protected route
r.GET("/api/me", RequireAuth(auth), func(c *gin.Context) {
user, _ := goten.UserFromContext(c.Request.Context())
c.JSON(http.StatusOK, user)
})
log.Fatal(r.Run(":8080"))
}The HTTP-level auth flow is identical to the Quick Start — r.Any("/api/auth/*action", ...) does not change request/response shapes. Use the curl walkthrough from Quick Start §8 to verify sign-up, sign-in, and protected routes.
-
No special adapter package. This page is everything. If you find yourself writing more glue than
gin.WrapHand the optional middleware in §3 above, double-check that you are using the righthttp.Handlerfrom Goten. -
Other frameworks (Echo, Chi, Fiber). Same principle: any framework that can mount an
http.Handlercan host Goten. The Gin-specific bits here are justgin.WrapHand thegin.HandlerFuncadapter; substitute the equivalents for your framework.