$ git clone https://github.com/angvp/tango $ cd tango/examples/jwt-api $ go run .
JWT API example
This example shows a JSON route protected by tanGO's optional auth/jwt
package. Its hardcoded key and -issue-token flag are development-only tools,
not a production credential or authentication endpoint.
git clone https://github.com/angvp/tango
cd tango/examples/jwt-api
go run . -issue-token reader-42
go run .
curl -H 'Authorization: Bearer <token>' http://localhost:8000/api/me
The address is TANGO_ADDR, else the PORT hosting platforms set, else :8000. Ctrl-C or SIGTERM shuts the server down gracefully.
A real application loads its keys from secure configuration and issues tokens
only after its own credential check. There is deliberately no unauthenticated
HTTP token endpoint in this example.
examples/jwt-api/main.go
packagemainimport("context""flag""fmt""net/http""os""os/signal""syscall""time""github.com/angvp/tango"tangojwt"github.com/angvp/tango/auth/jwt""github.com/angvp/tango/db")varexampleSecret=[]byte("example-only-secret-not-for-production-use")funcmain(){os.Exit(run())}funcrun()int{issueSubject:=flag.String("issue-token","","issue a development-only JWT for this subject and exit")check:=flag.Bool("check",false,"validate app registration and exit")flag.Parse()service,err:=newJWTService()iferr!=nil{fmt.Fprintln(os.Stderr,err)return1}if*issueSubject!=""{token,err:=service.Issue(*issueSubject,15*time.Minute)iferr!=nil{fmt.Fprintln(os.Stderr,err)return1}fmt.Println(token)return0}if*check{iferr:=tango.Check(exampleConfig(service));err!=nil{fmt.Fprintln(os.Stderr,"check failed:",err)return1}fmt.Println("check passed")return0}// Ctrl-C or SIGTERM cancels ctx, and ServeContext shuts down gracefully.ctx,stop:=signal.NotifyContext(context.Background(),os.Interrupt,syscall.SIGTERM)deferstop()config:=exampleConfig(service)fmt.Println("listening on",config.Addr)// The example has no database, so ServeContext gets none.iferr:=tango.ServeContext(ctx,config,nil,db.SQLite);err!=nil{fmt.Fprintln(os.Stderr,err)return1}return0}funcnewJWTService()(*tangojwt.Service,error){returntangojwt.NewService(tangojwt.Key{ID:"example-v1",Secret:exampleSecret},nil,"jwt-api-example","jwt-api-example",)}funcbuildHandler(service*tangojwt.Service)(http.Handler,error){registry,err:=tango.BuildRegistry(exampleConfig(service))iferr!=nil{returnnil,err}iferr:=registry.RunRegistration();err!=nil{returnnil,err}returnregistry.Routes().Handler()}funcexampleConfig(service*tangojwt.Service)tango.Config{me:=tangojwt.Require(func(ctx*tango.Context)error{claims,_:=tangojwt.FromContext(ctx.Context())returnctx.JSON(http.StatusOK,map[string]string{"subject":claims.Subject})})app:=tango.NewApp("jwt-api",func(registry*tango.Registry)error{returnregistry.Routes().Include("/api/",tango.URLs{tango.Path(http.MethodGet,"/me",me,tango.Name("me")),},tango.WithMiddleware(service.Middleware(tangojwt.BearerToken)))})// The address is TANGO_ADDR, else the PORT hosting platforms set, else :8000.config:=tango.LoadConfigFromEnv(tango.WithPortFromEnv())config.InstalledApps=[]tango.App{app}returnconfig}