Go
Same patterns as Python. Code is shorter because the JWT story is cleaner.
Pattern 2 — JWT validation (recommended for Go)
Most Go services are high-throughput; per-request HTTP calls to IdentSphere add latency you don't want. Validate JWTs locally instead.
go get github.com/golang-jwt/jwt/v5 github.com/MicahParks/keyfunc/v3
package main
import (
"context"
"fmt"
"net/http"
"os"
"time"
"github.com/MicahParks/keyfunc/v3"
"github.com/golang-jwt/jwt/v5"
)
var jwksURL = os.Getenv("IDENTSPHERE_URL") + "/.well-known/jwks.json"
func main() {
// Auto-refreshing JWKS cache
jwks, err := keyfunc.NewDefault([]string{jwksURL})
if err != nil {
panic(err)
}
mux := http.NewServeMux()
mux.Handle("/api/me", authMiddleware(jwks)(http.HandlerFunc(me)))
http.ListenAndServe(":8080", mux)
}
func authMiddleware(jwks keyfunc.Keyfunc) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("identsphere_at")
if err != nil {
http.Error(w, "unauthenticated", http.StatusUnauthorized)
return
}
tok, err := jwt.Parse(cookie.Value, jwks.Keyfunc)
if err != nil || !tok.Valid {
http.Error(w, "invalid token", http.StatusUnauthorized)
return
}
claims := tok.Claims.(jwt.MapClaims)
ctx := context.WithValue(r.Context(), "user", claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
func me(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value("user").(jwt.MapClaims)
fmt.Fprintf(w, "user=%s org=%s", claims["sub"], claims["org"])
}
That's a complete working auth-validating Go server in ~50 lines.
Pattern 1 — Proxy through IdentSphere
For login / signup / etc., forward to IdentSphere:
func loginHandler(w http.ResponseWriter, r *http.Request) {
req, _ := http.NewRequestWithContext(r.Context(), "POST",
os.Getenv("IDENTSPHERE_URL")+"/v1/auth/login", r.Body)
req.Header = r.Header.Clone()
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
defer resp.Body.Close()
// forward cookies
for _, c := range resp.Cookies() {
http.SetCookie(w, c)
}
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
Chi router
import "github.com/go-chi/chi/v5"
r := chi.NewRouter()
r.Group(func(r chi.Router) {
r.Use(authMiddlewareChi(jwks))
r.Get("/api/me", me)
})
Gin
Same pattern — wrap jwks.Keyfunc in gin.HandlerFunc. Sample in the
examples/gin-go-starter/ directory (coming v1.1).
Caveat: revocation lag
See the Python notes on revocation lag. Same trade-off applies in Go.