Giter VIP home page Giter VIP logo

gin-jwt's Introduction

JWT Middleware for Gin Framework

Run Tests GitHub tag GoDoc Go Report Card codecov codebeat badge Sourcegraph

This is a middleware for Gin framework.

It uses jwt-go to provide a jwt authentication middleware. It provides additional handler functions to provide the login api that will generate the token and an additional refresh handler that can be used to refresh tokens.

Security Issue

Simple HS256 JWT token brute force cracker. Effective only to crack JWT tokens with weak secrets. Recommendation: Use strong long secrets or RS256 tokens. See the jwt-cracker repository.

Usage

Download and install using go module:

export GO111MODULE=on
go get github.com/appleboy/gin-jwt/v2

Import it in your code:

import "github.com/appleboy/gin-jwt/v2"

Download and install without using go module:

go get github.com/appleboy/gin-jwt

Import it in your code:

import "github.com/appleboy/gin-jwt"

Example

Please see the example file and you can use ExtractClaims to fetch user data.

package main

import (
  "log"
  "net/http"
  "os"
  "time"

  jwt "github.com/appleboy/gin-jwt/v2"
  "github.com/gin-gonic/gin"
)

type login struct {
  Username string `form:"username" json:"username" binding:"required"`
  Password string `form:"password" json:"password" binding:"required"`
}

var (
  identityKey = "id"
  port        string
)

// User demo
type User struct {
  UserName  string
  FirstName string
  LastName  string
}

func init() {
  port = os.Getenv("PORT")
  if port == "" {
    port = "8000"
  }
}

func main() {
  engine := gin.Default()
  // the jwt middleware
  authMiddleware, err := jwt.New(initParams())
  if err != nil {
    log.Fatal("JWT Error:" + err.Error())
  }

  // register middleware
  engine.Use(handlerMiddleWare(authMiddleware))

  // register route
  registerRoute(engine, authMiddleware)

  // start http server
  if err = http.ListenAndServe(":"+port, engine); err != nil {
    log.Fatal(err)
  }
}

func registerRoute(r *gin.Engine, handle *jwt.GinJWTMiddleware) {
  r.POST("/login", handle.LoginHandler)
  r.NoRoute(handle.MiddlewareFunc(), handleNoRoute())

  auth := r.Group("/auth", handle.MiddlewareFunc())
  auth.GET("/refresh_token", handle.RefreshHandler)
  auth.GET("/hello", helloHandler)
}

func handlerMiddleWare(authMiddleware *jwt.GinJWTMiddleware) gin.HandlerFunc {
  return func(context *gin.Context) {
    errInit := authMiddleware.MiddlewareInit()
    if errInit != nil {
      log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
    }
  }
}

func initParams() *jwt.GinJWTMiddleware {

  return &jwt.GinJWTMiddleware{
    Realm:       "test zone",
    Key:         []byte("secret key"),
    Timeout:     time.Hour,
    MaxRefresh:  time.Hour,
    IdentityKey: identityKey,
    PayloadFunc: payloadFunc(),

    IdentityHandler: identityHandler(),
    Authenticator:   authenticator(),
    Authorizator:    authorizator(),
    Unauthorized:    unauthorized(),
    TokenLookup:     "header: Authorization, query: token, cookie: jwt",
    // TokenLookup: "query:token",
    // TokenLookup: "cookie:token",
    TokenHeadName: "Bearer",
    TimeFunc:      time.Now,
  }
}

func payloadFunc() func(data interface{}) jwt.MapClaims {
  return func(data interface{}) jwt.MapClaims {
    if v, ok := data.(*User); ok {
      return jwt.MapClaims{
        identityKey: v.UserName,
      }
    }
    return jwt.MapClaims{}
  }
}

func identityHandler() func(c *gin.Context) interface{} {
  return func(c *gin.Context) interface{} {
    claims := jwt.ExtractClaims(c)
    return &User{
      UserName: claims[identityKey].(string),
    }
  }
}

func authenticator() func(c *gin.Context) (interface{}, error) {
  return func(c *gin.Context) (interface{}, error) {
    var loginVals login
    if err := c.ShouldBind(&loginVals); err != nil {
      return "", jwt.ErrMissingLoginValues
    }
    userID := loginVals.Username
    password := loginVals.Password

    if (userID == "admin" && password == "admin") || (userID == "test" && password == "test") {
      return &User{
        UserName:  userID,
        LastName:  "Bo-Yi",
        FirstName: "Wu",
      }, nil
    }
    return nil, jwt.ErrFailedAuthentication
  }
}

func authorizator() func(data interface{}, c *gin.Context) bool {
  return func(data interface{}, c *gin.Context) bool {
    if v, ok := data.(*User); ok && v.UserName == "admin" {
      return true
    }
    return false
  }
}

func unauthorized() func(c *gin.Context, code int, message string) {
  return func(c *gin.Context, code int, message string) {
    c.JSON(code, gin.H{
      "code":    code,
      "message": message,
    })
  }
}

func handleNoRoute() func(c *gin.Context) {
  return func(c *gin.Context) {
    claims := jwt.ExtractClaims(c)
    log.Printf("NoRoute claims: %#v\n", claims)
    c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
  }
}

func helloHandler(c *gin.Context) {
  claims := jwt.ExtractClaims(c)
  user, _ := c.Get(identityKey)
  c.JSON(200, gin.H{
    "userID":   claims[identityKey],
    "userName": user.(*User).UserName,
    "text":     "Hello World.",
  })
}

Demo

Please run _example/basic/server.go file and listen 8000 port.

go run _example/basic/server.go

Download and install httpie CLI HTTP client.

Login API

http -v --json POST localhost:8000/login username=admin password=admin

Output screenshot

api screenshot

Refresh token API

http -v -f GET localhost:8000/auth/refresh_token "Authorization:Bearer xxxxxxxxx"  "Content-Type: application/json"

Output screenshot

api screenshot

Hello world

Please login as admin and password as admin

http -f GET localhost:8000/auth/hello "Authorization:Bearer xxxxxxxxx"  "Content-Type: application/json"

Response message 200 OK:

HTTP/1.1 200 OK
Content-Length: 24
Content-Type: application/json; charset=utf-8
Date: Sat, 19 Mar 2016 03:02:57 GMT

{
  "text": "Hello World.",
  "userID": "admin"
}

Authorization

Please login as test and password as test

http -f GET localhost:8000/auth/hello "Authorization:Bearer xxxxxxxxx"  "Content-Type: application/json"

Response message 403 Forbidden:

HTTP/1.1 403 Forbidden
Content-Length: 62
Content-Type: application/json; charset=utf-8
Date: Sat, 19 Mar 2016 03:05:40 GMT
Www-Authenticate: JWT realm=test zone

{
  "code": 403,
  "message": "You don't have permission to access."
}

Cookie Token

Use these options for setting the JWT in a cookie. See the Mozilla documentation for more information on these options.

  SendCookie:       true,
  SecureCookie:     false, //non HTTPS dev environments
  CookieHTTPOnly:   true,  // JS can't modify
  CookieDomain:     "localhost:8080",
  CookieName:       "token", // default jwt
  TokenLookup:      "cookie:token",
  CookieSameSite:   http.SameSiteDefaultMode, //SameSiteDefaultMode, SameSiteLaxMode, SameSiteStrictMode, SameSiteNoneMode

Login request flow (using the LoginHandler)

PROVIDED: LoginHandler

This is a provided function to be called on any login endpoint, which will trigger the flow described below.

REQUIRED: Authenticator

This function should verify the user credentials given the gin context (i.e. password matches hashed password for a given user email, and any other authentication logic). Then the authenticator should return a struct or map that contains the user data that will be embedded in the jwt token. This might be something like an account id, role, is_verified, etc. After having successfully authenticated, the data returned from the authenticator is passed in as a parameter into the PayloadFunc, which is used to embed the user identifiers mentioned above into the jwt token. If an error is returned, the Unauthorized function is used (explained below).

OPTIONAL: PayloadFunc

This function is called after having successfully authenticated (logged in). It should take whatever was returned from Authenticator and convert it into MapClaims (i.e. map[string]interface{}). A typical use case of this function is for when Authenticator returns a struct which holds the user identifiers, and that struct needs to be converted into a map. MapClaims should include one element that is [IdentityKey (default is "identity"): some_user_identity]. The elements of MapClaims returned in PayloadFunc will be embedded within the jwt token (as token claims). When users pass in their token on subsequent requests, you can get these claims back by using ExtractClaims.

OPTIONAL: LoginResponse

After having successfully authenticated with Authenticator, created the jwt token using the identifiers from map returned from PayloadFunc, and set it as a cookie if SendCookie is enabled, this function is called. It is used to handle any post-login logic. This might look something like using the gin context to return a JSON of the token back to the user.

Subsequent requests on endpoints requiring jwt token (using MiddlewareFunc)

PROVIDED: MiddlewareFunc

This is gin middleware that should be used within any endpoints that require the jwt token to be present. This middleware will parse the request headers for the token if it exists, and check that the jwt token is valid (not expired, correct signature). Then it will call IdentityHandler followed by Authorizator. If Authorizator passes and all of the previous token validity checks passed, the middleware will continue the request. If any of these checks fail, the Unauthorized function is used (explained below).

OPTIONAL: IdentityHandler

The default of this function is likely sufficient for your needs. The purpose of this function is to fetch the user identity from claims embedded within the jwt token, and pass this identity value to Authorizator. This function assumes [IdentityKey: some_user_identity] is one of the attributes embedded within the claims of the jwt token (determined by PayloadFunc).

OPTIONAL: Authorizator

Given the user identity value (data parameter) and the gin context, this function should check if the user is authorized to be reaching this endpoint (on the endpoints where the MiddlewareFunc applies). This function should likely use ExtractClaims to check if the user has the sufficient permissions to reach this endpoint, as opposed to hitting the database on every request. This function should return true if the user is authorized to continue through with the request, or false if they are not authorized (where Unauthorized will be called).

Logout Request flow (using LogoutHandler)

PROVIDED: LogoutHandler

This is a provided function to be called on any logout endpoint, which will clear any cookies if SendCookie is set, and then call LogoutResponse.

OPTIONAL: LogoutResponse

This should likely just return back to the user the http status code, if logout was successful or not.

Refresh Request flow (using RefreshHandler)

PROVIDED: RefreshHandler:

This is a provided function to be called on any refresh token endpoint. If the token passed in is was issued within the MaxRefreshTime time frame, then this handler will create/set a new token similar to the LoginHandler, and pass this token into RefreshResponse

OPTIONAL: RefreshResponse:

This should likely return a JSON of the token back to the user, similar to LoginResponse

Failures with logging in, bad tokens, or lacking privileges

OPTIONAL Unauthorized:

On any error logging in, authorizing the user, or when there was no token or a invalid token passed in with the request, the following will happen. The gin context will be aborted depending on DisabledAbort, then HTTPStatusMessageFunc is called which by default converts the error into a string. Finally the Unauthorized function will be called. This function should likely return a JSON containing the http error code and error message to the user.

gin-jwt's People

Contributors

a180285 avatar actumn avatar adwindone avatar andygrunwald avatar andyinabox avatar appleboy avatar arkalon76 avatar asxcandrew avatar bmoix avatar changkun avatar cmwright avatar dependabot[bot] avatar dlaub3 avatar inful avatar jbfm avatar jesusnoseq avatar jorritsalverda avatar kingcw avatar manisharma7575 avatar morenocarullo avatar panjf2000 avatar piusnyakoojo avatar rezkam avatar rlacko58 avatar rogary avatar royalrick avatar starballoon avatar thor-x86 avatar undeadbanegithub avatar yujiahaol68 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gin-jwt's Issues

User Info into Gin Default Logger

Hi All, I'm trying to include the logged user info into Gin Default Log, but Go won't allow me to include the gin-jwt import into logger.go file, because it creates "import cycle".
Has anyone faced this?

Thanks in Advance.

Doesn't build in DOcker

HI i have a BAAS that i built using your gin-jwt to authenticate routes. It works just fine in localhost,
running it using "go run server.go" , However when i build it using docker i get this error message.

src/work/xprincipia/backend/gin/jwt.go:34: cannot use func literal (type func(string, string, *"gopkg.in/gin-gonic/gin.v1".Context) (string, bool)) as type func(string, string, *"github.com/gin-gonic/gin".Context) (string, bool) in field value
src/work/xprincipia/backend/gin/jwt.go:38: cannot use func literal (type func(string, "gopkg.in/gin-gonic/gin.v1".Context) bool) as type func(string, "github.com/gin-gonic/gin".Context) bool in field value
src/work/xprincipia/backend/gin/jwt.go:44: cannot use func literal (type func(
"gopkg.in/gin-gonic/gin.v1".Context, int, string)) as type func(
"github.com/gin-gonic/gin".Context, int, string) in field value

It's wierd because, I didn't get this error last week. Anyways, was it a new update that caused this. Any help would be appreciated

// the jwt middleware
var authMiddleware = &jwt.GinJWTMiddleware{
	Realm:      "test zone",
	Key:        []byte("secret key"),
	Timeout:    time.Hour,
	MaxRefresh: time.Hour,
	Authenticator: func(userId string, password string, c *gin.Context) (string, bool) {
		user := gorm.User{}
		passwordBytes := []byte(password)

		if user.GetUserByUsername(userId) {
			hashedPassword := user.HashedPassword
			err := bcrypt.CompareHashAndPassword(hashedPassword, passwordBytes)
			if err == nil {
				glog.Info("USER LOG IN SUCCESSFUL...")
				return userId, true
			}
			glog.Info(err)
		}
		return userId, false
	},
	Authorizator: func(userId string, c *gin.Context) bool {
		//check if this user is in the db based on the jwt
		return gorm.IsUserinDBbyUsername(userId)
	},Unauthorized: func(c *gin.Context, code int, message string) {
		c.JSON(code, gin.H{
			"code":    code,
			"message": message,
		})
	},
	// TokenLookup is a string in the form of "<source>:<name>" that is used
	// to extract token from the request.
	// Optional. Default value "header:Authorization".
	// Possible values:
	// - "header:<name>"
	// - "query:<name>"
	// - "cookie:<name>"
	TokenLookup: "header:Authorization",
	// TokenLookup: "query:token",
	// TokenLookup: "cookie:token",
}

Here is jwt.go

Why is Authenticator func a required?

Thanks for creating this great jwt middleware. Authenticator func is only called by LoginHandler(). If I want to write MyOwnLoginhandler() where I create my own claims and signing, I wouldn't need to set Authenticator then, but it is requirement set in the MiddlewareInit(). Right now I set Authenticator to return "", true.

Question... Would moving the check for Authenticator == nil in MiddlewareInit() to the LoginHandler() function be better suited? or maybe making this field optional? That way its not a hard requirement for those who wouldn't use LoginHandler.

the gin-gonic version is different.

Hi, @appleboy

last tag v2.1.1, you use github.com/gin-gonic/gin, but the latest v2.1.2 you use gopkg.in/gin-gonic/gin.v1, the change will broke the program who use github.com/gin-gonic/gin

Panic on refresh_token

Hi ,
Im trying to run the refresh token handler and it`s get panic on the converting of

origIat := int64(token.Claims["orig_iat"].(float64))

It look like the claim is nill.

`
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] POST   /login                    --> gopkg.in/appleboy/gin-jwt%2ev1.(*GinJWTMiddleware).LoginHandler-fm (3 handlers)
[GIN-debug] GET    /auth/hello               --> main.HelloHandler (4 handlers)
[GIN-debug] GET    /auth/refresh_token       --> gopkg.in/appleboy/gin-jwt%2ev1.(*GinJWTMiddleware).RefreshHandler-fm (4 handlers)
2947 :8000


�[31m2016/07/04 18:24:56 [Recovery] panic recovered:
GET /auth/refresh_token HTTP/1.1
Host: localhost:8000
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,he;q=0.6
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Njc2NDg3ODIsImlkIjoiYWRtaW4ifQ.HD_0Lx9UGF3yQMJZCvbPadB7_rKVdtaPD-vIqH4FA-o
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json
Dnt: 1
Postman-Token: 27f71581-af40-e08a-30d8-ddd81e89247a
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36


interface conversion: interface is nil, not float64
/usr/local/go/src/runtime/panic.go:423 (0x42a2c9)
    gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
/usr/local/go/src/runtime/iface.go:218 (0x40d3f5)
    assertE2T: panic(&TypeAssertionError{"", "", *t._string, ""})
/home/mik/go-programes/src/gopkg.in/appleboy/gin-jwt.v1/auth_jwt.go:199 (0x49a81e)
    (*GinJWTMiddleware).RefreshHandler: origIat := int64(token.Claims["orig_iat"].(float64))

`

Use with gin v1

Hi,

I get a signature error while using it with the gin package "gopkg.in/gin-gonic/gin.v1"

However If i change gin-jwt gin import from "github.com/gin-gonic/gin" to "gopkg.in/gin-gonic/gin.v1" it works.

What's the best practice here ?

the Demo for Login API command is error...

It should be "http -v --json POST localhost:8000/login username=admin password=admin", or "curl -v -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' localhost:8000/login"

What are realms?

Hey, I'm new to JWT and Go in general. I'm confused as to what a Realm is in the context of JWT's. I've looked everywhere I could and gin-jwt seems to be the only place that references Realms. Could someone explain it to me?

Supporting additional params to the Authenticator

At the moment the Authenticator has the following signature: func(username string, password string, c *gin.Context).

This works perfectly when you only have a username/password that you'd like to auth on. In our use case we have a username/password but also need to auth an OTP.

Even though the GIN context is being passed down to the Authenticator one does not have access to the c.Request.Body if you wanted to manually parse out any extra params because the c.Request.Body has already been read and cleared by the time it gets to the Authenticator.

It would be preferable to do the auth in one request instead of first getting a JWT token and then doing the OTP auth separate.

Is additional parameter handling a feature that can be added to gin-jwt or is this something that I need to try and fudge in using middleware that copies the c.Request.Body and records it in the context?

How do you get claims within a route?

I would like to access the current identity of the authenticated user in an authenticated route what is the procedure for doing this (it seems like this is not documented)?

different Authorizator depending on Router Groups

Hi,

(thx for having merged so quickly my PR on Context injection ^^)

I'm facing an issue, and I think it may be a functional / logical problem in Authorization implementation and / or limitations cause by lack of informations about groups in gin.Context.

For example, here are my groups definitions for admin/users :

    admin := r.Group("/admin")
    admin.Use(authMiddleware.MiddlewareFunc())
    {
        users := admin.Group("/users")
        users.GET("/:username", user.ByUsernameHandler)
        users.POST("", registration.RegisterHandler)
        users.GET("", user.AllUsersHandler)
    }

By using your Authorizator callback, I have to be aware of two informations :

  • roles of user (stored in my DB)
  • which route matches to the request and in which group(s) it belongs

Each leads me to an issue :

  • User roles can be accessed only by querying for the second time (it has already been queried in Authenticator Handler). I've been trying to set user in context with c.Set("User", user) in Authenticator and access it in Authorizator, but unsuccessfully, c.Get return false for "exists" return param…
  • gin.Context does not contain Group… Just handler name…

Should I implement my own solution like writing a specific Middleware, with an string argument telling me what group is called ? Or is there any more elegant way to fix this ?

can't use。

1

.\main.go:50: cannot use Authenticator (type func(string, string, *"j99.io/app/cloud_token_api/vendor/github.com/gin-gonic/gin".Context) (string, bool)) as type func(string, string, *"github.com/gin-gonic/gin".Context) (string, bool) in field value
.\main.go:51: cannot use Authorizator (type func(string, *"j99.io/app/cloud_token_api/vendor/github.com/gin-gonic/gin".Context) bool) as type func(string, *"github.com/gin-gonic/gin".Context) bool in field value
.\main.go:52: cannot use Unauthorized (type func(*"j99.io/app/cloud_token_api/vendor/github.com/gin-gonic/gin".Context, int, string)) as type func(*"github.com/gin-gonic/gin".Context, int, string) in field value
.\main.go:81: cannot use authMiddleware.LoginHandler (type func(*"github.com/gin-gonic/gin".Context)) as type "j99.io/app/cloud_token_api/vendor/github.com/gin-gonic/gin".HandlerFunc in argument to app.RouterGroup.POST

Can't find how to access user from protected route

I'm trying to access the current userId from a very simple /me route returning the currently logged user informations. I've read in your code that it's supposed to be set at the key "userId" in c, but c.Get("userId") tells me it doesn't exist in my context. What am I doing wrong ?

in main :

auth := r.Group("/users")
    auth.Use(authMiddleware.MiddlewareFunc())
    {
        auth.GET("/me", user.Me)
        auth.GET("/refresh_token", authMiddleware.RefreshHandler)
    }

my handler :

func Me(c *gin.Context) {
    username, exists := c.Get("userId")

    log.Print(username) //return nil
    log.Print(exists) //return false
}

Thx !

userID vs. username in LoginHandler

I'm not convinced this is even an issue. Feel free to disregard.

The LoginHandler function and GinJWTMiddleware function signatures are a little misleading.

For example:

  • Authenticator has a parameter named userID, but it is passed the loginVals.Username.
  • PayloadFunc has a parameter named userID, but it is passed the loginVals.Username, even if the Authenticator function returns a user id.
  • Authorizator has a parameter named userID, and it is passed the userID (not the username) which I think is correct, but different from the way other functions are being called.

It is pretty minor. Just wanted to let you know there was a little friction getting started. It might also be tricky to change any of this without breaking backwards compatibility.

Thanks for the great work!

Fix readme or import

Need fix Readme or code, example/server.go imports "github.com/appleboy/gin-jwt" and i don't have it because

Install gin-gwt v2 version for jwt-go v3 version. To get the package, execute:

$ go get gopkg.in/appleboy/gin-jwt.v2

Unable to post from postman

I have a problem posting on postman, my headers are Content-Type: application/json and my body (I've tested both form-data and form-url-encoded) key=value are: username: chaofanman password:password and it doesn't work. I always get {"code":400,"message":"Missing Username or Password"}. However, when i post using httpie it is totally find. It also works on raw as a json however. What am i doing wrong?

refresh token MaxRefresh question.

Hi, I set Timeout and MaxRefresh all to 1 minutes,when token expired after one minute,I use old token in the header and request refresh_token api but still return expired.
If I use ajax to request my api, but found token expired,ajax need request refresh_token to get a new one,but response said expired,so how to resolve it?? thx!

return a code in loginhandler

loginhandler Reply will be of the form {"token": "TOKEN", "expire": "xxx-xx"}, how about add a code to it, just like when we failed on authrention

HttpOnly cookie

Is there any way to set token in cookie when authenticator callback fired?

Allow guest access to "protected" routes

I'm trying to just get session information into my handlers. For that I want a route to be accessible by authorised users as well as guests. Can gin_jwt library handle this situation? I'm not sure how to avoid the auth header empty error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.