This package provides json web token (jwt) middleware for goLang http servers

Related tags

jwt-auth
Overview

Build Status Coverage Status Go Report Card GoDoc

jwt-auth

jwt auth middleware in goLang.

If you're interested in using sessions, checkout my sessions library!

README Contents:

  1. Quickstart
  2. Performance
  3. Goals
  4. Design
  5. API
  6. TODO
  7. Test Coverage
  8. License

Quickstart

package main

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

  "github.com/adam-hanna/jwt-auth/jwt"
)

var restrictedRoute jwt.Auth

var restrictedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Welcome to the secret area!"))
})

var regularHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Hello, World!"))
})

func main() {
  authErr := jwt.New(&restrictedRoute, jwt.Options{
    SigningMethodString:   "RS256",
    PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
    PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
    RefreshTokenValidTime: 72 * time.Hour,
    AuthTokenValidTime:    15 * time.Minute,
    Debug:                 false,
    IsDevEnv:              true,
  })
  if authErr != nil {
    log.Println("Error initializing the JWT's!")
    log.Fatal(authErr)
  }

  http.HandleFunc("/", regularHandler)
  // this will never be available because we never issue tokens
  // see login_logout example for how to provide tokens
  http.Handle("/restricted", restrictedRoute.Handler(restrictedHandler))

  log.Println("Listening on localhost:3000")
  http.ListenAndServe("127.0.0.1:3000", nil)
}

Performance

YMMV

$ cd jwt && go test -bench=.

BenchmarkBaseServer-2                        10000      137517 ns/op
BenchmarkValidAuthTokenWithCookies-2          5000      303160 ns/op
BenchmarkExpiredAuthTokenWithCookies-2        5000      323933 ns/op
PASS
ok    github.com/adam-hanna/jwt-auth/jwt  15.463s

Goals

It is important to understand the objective of this auth architecture. It certainly is not an applicable design for all use cases. Please read and understand the goals, below, and make changes to your own workflow to suit your specific needs.

  1. Protection of non-critical api's (e.g. not meant for financial, healthcare, gov't, etc. services)
  2. Stateless
  3. User sessions
  4. CSRF protection
  5. Web and/or mobile

Design

The design of this auth system is based around the three major components, listed below.

  1. Short-lived (minutes) JWT Auth Token
  2. Longer-lived (hours / days) JWT Refresh Token
  3. CSRF secret string

1. Short-lived (minutes) JWT Auth Token

The short-lived jwt auth token allows the user to make stateless requests to protected api endpoints. It has an expiration time of 15 minutes by default and will be refreshed by the longer-lived refresh token.

2. Longer-lived (hours/days) JWT Refresh Token

This longer-lived token will be used to update the auth tokens. These tokens have a 72 hour expiration time by default which will be updated each time an auth token is refreshed.

These refresh tokens contain an id which can be revoked by an authorized client.

3. CSRF Secret String

A CSRF secret string will be provided to each client and will be identical the CSRF secret in the auth and refresh tokens and will change each time an auth token is refreshed. These secrets will live in an "X-CSRF-Token" response header, by default, but the header key can be set as an option. These secrets will be sent along with the auth and refresh tokens on each api request.

When request are made to protected endpoint, this CSRF secret needs to be sent to the server either as a hidden form value with a name of "X-CSRF-Token", in the request header with the key of "X-CSRF-Token", or in the "Authorization" request header with a value of "Bearer " + token. This secret will be checked against the secret provided in the auth token in order to prevent CSRF attacks. It will be refreshed each time the auth token is refreshed from the refresh token.

Cookies or Bearer Tokens?

This API is setup to either use cookies (default) or bearer tokens. To use bearer tokens, set the BearerTokens option equal to true in the config settings.

When using bearer tokens, you'll need to include the auth and (optionally [the]) refresh jwt's (along with your csrf secret) in each request. Include them in the request headers. The keys can be defined in the auth options, but default to "X-Auth-Token" and "X-Refresh-Token", respectively. See the bearerTokens example for sample code of both.

Ideally, if using bearer tokens, they should be stored in a location that cannot be accessed with javascript. You want to be able to separate your csrf secret from your jwt's. If using web, I suggest using cookies. If using mobile, store these in a secure manner!

If you are using cookies, the auth and refresh jwt's will automatically be included. You only need to include the csrf token.

API

Create a new jwt middleware

var restrictedRoute jwt.Auth

JWT middleware options

type Options struct {
  SigningMethodString   string // one of "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512"
  PrivateKeyLocation    string // only for RSA and ECDSA signing methods; only required if VerifyOnlyServer is false
  PublicKeyLocation     string // only for RSA and ECDSA signing methods
  HMACKey               []byte // only for HMAC-SHA signing method
  VerifyOnlyServer      bool // false = server can verify and issue tokens (default); true = server can only verify tokens
  BearerTokens          bool // false = server uses cookies to transport jwts (default); true = server uses request headers
  RefreshTokenValidTime time.Duration
  AuthTokenValidTime    time.Duration
  AuthTokenName         string // defaults to "AuthToken" for cookies and "X-Auth-Token" for bearer tokens
  RefreshTokenName      string // defaults to "RefreshToken" for cookies and "X-Refresh-Token" for bearer tokens
  CSRFTokenName         string // defaults to "X-CSRF-Token"
  Debug                 bool // true = more logs are shown
  IsDevEnv              bool // true = in development mode; this sets http cookies (if used) to insecure; false = production mode; this sets http cookies (if used) to secure
}

ClaimsType

type ClaimsType struct {
  // Standard claims are the standard jwt claims from the ietf standard
  // https://tools.ietf.org/html/rfc7519
  jwt.StandardClaims
  Csrf               string
  CustomClaims       map[string]interface{}
}

Note that there is a "CustomClaims" map that allows you to set whatever you want. See "IssueTokenClaims" and "GrabTokenClaims", below, for more.

Initialize new JWT middleware

authErr := jwt.New(&restrictedRoute, jwt.Options{
  SigningMethodString:   "RS256",
  PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
  PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
  RefreshTokenValidTime: 72 * time.Hour,
  AuthTokenValidTime:    15 * time.Minute,
  Debug:                 false,
  IsDevEnv:              true,
})
if authErr != nil {
  log.Println("Error initializing the JWT's!")
  log.Fatal(authErr)
}

Handle a restricted route (see below for integration with popular frameworks)

// outside of main()
var restrictedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  csrfSecret := w.Header().Get("X-CSRF-Token")
  claims, err := restrictedRoute.GrabTokenClaims(r)
  log.Println(claims)
  
  if err != nil {
    http.Error(w, "Internal Server Error", 500)
  } else {
    templates.RenderTemplate(w, "restricted", &templates.RestrictedPage{ csrfSecret, claims.CustomClaims["Role"].(string) })
  }
})

func main() {
  ...
  http.Handle("/restricted", restrictedRoute.Handler(restrictedHandler))

  log.Println("Listening on localhost:3000")
  http.ListenAndServe("127.0.0.1:3000", nil)
}

Issue new tokens and CSRF secret (for instance, when a user provides valid login credentials)

// in a handler func
claims := jwt.ClaimsType{}
claims.StandardClaims.Id = "fakeTokenId123"
claims.CustomClaims = make(map[string]interface{})
claims.CustomClaims["Role"] = "user"

err := restrictedRoute.IssueNewTokens(w, &claims)
if err != nil {
  http.Error(w, "Internal Server Error", 500)
}

w.WriteHeader(http.StatusOK)

Note: a token Id must be provided if you'd later like the ability to revoke this token!

Get a CSRF secret from a response

// in a handler func
// note: this works because if the middleware has made it this far, the JWT middleware has written a CSRF secret to the response writer (w)
csrfSecret := w.Header().Get("X-CSRF-Token")

Get the expiration time of the refresh token, in Unix time

// in a handler func
// note: this works because if the middleware has made it this far, the JWT middleware has written this to the response writer (w)
// note: also, this won't be exact and may be a few milliseconds off from the token's actual expiry
refreshExpirationTime := w.Header().Get("Refresh-Expiry")

Get the expiration time of the auth token, in Unix time

// in a handler func
// note: this works because if the middleware has made it this far, the JWT middleware has written this to the response writer (w)
// note: also, this won't be exact and may be a few milliseconds off from the token's actual expiry
authExpirationTime := w.Header().Get("Auth-Expiry")

Get claims from a request

// in a handler func
claims, err := restrictedRoute.GrabTokenClaims(r)
log.Println(claims)

Nullify auth and refresh tokens (for instance, when a user logs out)

// in a handler func
err = restrictedRoute.NullifyTokens(w, r)
if err != nil {
  http.Error(w, "Internal Server Error", 500)
  return
}

http.Redirect(w, r, "/login", 302)

Token Id checker

A function used to check if a refresh token id has been revoked. You can either use a blacklist of revoked tokens, or a whitelist of allowed tokens. Your call. This function simply needs to return true if the token id has not been revoked. This function is run everytime an auth token is refreshed.

var restrictedRoute jwt.Auth

// create a database of refresh tokens
// map key is the jti (json token identifier)
// the val doesn't represent anything but could be used to hold "valid", "revoked", etc.
// in the real world, you would store these in your db. This is just an example.
var refreshTokens map[string]string

restrictedRoute.SetCheckTokenIdFunction(CheckRefreshToken)

func CheckRefreshToken(jti string) bool {
  return refreshTokens[jti] != ""
}

Token Id revoker

A function that adds a token id to a blacklist of revoked tokens, or revokes it from a whitelist of allowed tokens (however you'd like to do it).

var restrictedRoute jwt.Auth

// create a database of refresh tokens
// map key is the jti (json token identifier)
// the val doesn't represent anything but could be used to hold "valid", "revoked", etc.
// in the real world, you would store these in your db. This is just an example.
var refreshTokens map[string]string

restrictedRoute.SetRevokeTokenFunction(DeleteRefreshToken)

func DeleteRefreshToken(jti string) error {
  delete(refreshTokens, jti)
  return nil
}

500 error handling

Set the response to a 500 error.

var restrictedRoute jwt.Auth

restrictedRoute.SetErrorHandler(myErrorHandler)

var myErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  http.Error(w, "I pitty the fool who has a 500 internal server error", 500)
  return
})

401 unauthorized handling

Set the response to a 401 unauthorized request

var restrictedRoute jwt.Auth

restrictedRoute.SetUnauthorizedHandler(MyUnauthorizedHandler)

var MyUnauthorizedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  http.Error(w, "I pitty the fool who is unauthorized", 401)
  return
})

Integration with popular goLang web Frameworks (untested)

The architecture of this package was inspired by Secure, so I believe the integrations, below, should work. But they are untested.

Echo

package main

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

	"github.com/adam-hanna/jwt-auth/jwt"
	"github.com/labstack/echo"
)

var restrictedRoute jwt.Auth

func main() {
	authErr := jwt.New(&restrictedRoute, jwt.Options{
		SigningMethodString:   "RS256",
		PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
		PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
		RefreshTokenValidTime: 72 * time.Hour,
		AuthTokenValidTime:    15 * time.Minute,
		Debug:                 false,
		IsDevEnv:              true,
	})
	if authErr != nil {
		log.Println("Error initializing the JWT's!")
		log.Fatal(authErr)
	}

	e := echo.New()

	e.GET("/public", func(c echo.Context) error {
		c.String(http.StatusOK, "Hello, world!")
		return nil
	})

	e.GET("/restricted", func(c echo.Context) error {
		c.String(http.StatusOK, "Restricted")
		return nil
	}, echo.WrapMiddleware(restrictedRoute.Handler))

	e.Logger.Fatal(e.Start(":1323"))
}

Gin

// main.go
package main

import (
  "log"

  "github.com/gin-gonic/gin"
  "github.com/adam-hanna/jwt-auth/jwt"
)

var restrictedRoute jwt.Auth

func main() {
  authErr := jwt.New(&restrictedRoute, jwt.Options{
    SigningMethodString:   "RS256",
    PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
    PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
    RefreshTokenValidTime: 72 * time.Hour,
    AuthTokenValidTime:    15 * time.Minute,
    Debug:                 false,
    IsDevEnv:              true,
  })
  if authErr != nil {
    log.Println("Error initializing the JWT's!")
    log.Fatal(authErr)
  }
  restrictedFunc := func() gin.HandlerFunc {
    return func(c *gin.Context) {
      err := restrictedRoute.Process(c.Writer, c.Request)

      // If there was an error, do not continue.
      if err != nil {
        return
      }

      c.Next()
    }
  }()

  router := gin.Default()
  router.Use(restrictedFunc)

  router.GET("/", func(c *gin.Context) {
    c.String(200, "Restricted")
  })

  router.Run("127.0.0.1:3000")
}

Goji

// main.go
package main

import (
  "net/http"
  "log"

  "github.com/adam-hanna/jwt-auth/jwt"
  "github.com/zenazn/goji"
  "github.com/zenazn/goji/web"
)

var restrictedRoute jwt.Auth

func main() {
  authErr := jwt.New(&restrictedRoute, jwt.Options{
    SigningMethodString:   "RS256",
    PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
    PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
    RefreshTokenValidTime: 72 * time.Hour,
    AuthTokenValidTime:    15 * time.Minute,
    Debug:                 false,
    IsDevEnv:              true,
  })
  if authErr != nil {
    log.Println("Error initializing the JWT's!")
    log.Fatal(authErr)
  }

  goji.Get("/", func(c web.C, w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Restricted"))
  })
  goji.Use(restrictedRoute.Handler)
  goji.Serve() // Defaults to ":8000".
}

Iris

//main.go
package main

import (
  "log"

  "github.com/kataras/iris"
  "github.com/adam-hanna/jwt-auth/jwt"
)

var restrictedRoute jwt.Auth

func main() {
  authErr := jwt.New(&restrictedRoute, jwt.Options{
    SigningMethodString:   "RS256",
    PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
    PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
    RefreshTokenValidTime: 72 * time.Hour,
    AuthTokenValidTime:    15 * time.Minute,
    Debug:                 false,
    IsDevEnv:              true,
  })
  if authErr != nil {
    log.Println("Error initializing the JWT's!")
    log.Fatal(authErr)
  }

  iris.UseFunc(func(c *iris.Context) {
    err := restrictedRoute.Process(c.ResponseWriter, c.Request)

    // If there was an error, do not continue.
    if err != nil {
      return
    }

    c.Next()
  })

  iris.Get("/home", func(c *iris.Context) {
    c.SendStatus(200,"Restricted")
  })

  iris.Listen(":8080")

}

Negroni

Note this implementation has a special helper function called HandlerFuncWithNext.

// main.go
package main

import (
  "net/http"
  "log"

  "github.com/codegangsta/negroni"
  "github.com/adam-hanna/jwt-auth/jwt"
)

var restrictedRoute jwt.Auth

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Restricted"))
  })

  authErr := jwt.New(&restrictedRoute, jwt.Options{
    SigningMethodString:   "RS256",
    PrivateKeyLocation:    "keys/app.rsa",     // `$ openssl genrsa -out app.rsa 2048`
    PublicKeyLocation:     "keys/app.rsa.pub", // `$ openssl rsa -in app.rsa -pubout > app.rsa.pub`
    RefreshTokenValidTime: 72 * time.Hour,
    AuthTokenValidTime:    15 * time.Minute,
    Debug:                 false,
    IsDevEnv:              true,
  })
  if authErr != nil {
    log.Println("Error initializing the JWT's!")
    log.Fatal(authErr)
  }

  n := negroni.Classic()
  n.Use(negroni.HandlerFunc(restrictedRoute.HandlerFuncWithNext))
  n.UseHandler(mux)

  n.Run("127.0.0.1:3000")
}

TODO

  1. Clean up the tests

Test Coverage

$ cd jwt && go test -coverprofile=test/coverage.out

coverage: 84.7% of statements

$ go tool cover -html=test/coverage.out

License

The MIT License (MIT)

Copyright (c) 2016 Adam Hanna

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Issues
  • Error in Quickstart Example

    Error in Quickstart Example

    I did a "go get go get github.com/adam-hanna/jwt-auth/src" then I tried to run the QuickStart example with "go run quickstart.go" and I get the error:

    # github.com/adam-hanna/jwt-auth/src
    ../github.com/adam-hanna/jwt-auth/src/jwt.go:20: undefined: jwt.StandardClaims
    

    I assume I am missing a library can you tell me what it is?

    opened by p4tin 7
  • Added possibility to disable CSRF VALIDATION

    Added possibility to disable CSRF VALIDATION

    I don't understand how to create a valid csrf token!

    opened by amreo 5
  • verify request jwt alg everytime

    verify request jwt alg everytime

    opened by se77en 4
  • Introduced proper header auth

    Introduced proper header auth

    @adam-hanna Just in case you want to consider idiomatic way of auth via headers, I like the library, so modified it to better suit single page apps/mobile auth.

    bug enhancement 
    opened by ruseinov 4
  • Unexported function when work with Gin and Iris

    Unexported function when work with Gin and Iris

    opened by se77en 3
  • Echo example and odd behaviour

    Echo example and odd behaviour

    Hi,

    First of all, echo example seems kind of outdated. I need to use something like this, to make things work (with echo v3):

    e.Use(echo.WrapMiddleware(restrictedRoute.Handler))
    

    and (with echo v2):

    e.Use(standard.WrapMiddleware(restrictedRoute.Handler))
    

    Second, it seems that this thing works really weird in here. When i define routes:

    /foo
    /bar
    --- here, i'm using restrictedRoute handler as middleware ----
    /baz
    /bam
    

    Instead of "protecting" routes /baz and /bam it goes global and includes routes /foo and /bar. Why is that?

    opened by krzysztofantczak 2
  • usage of log instead of myLog in auth-util.go

    usage of log instead of myLog in auth-util.go

    Hey you used the function log instead of using myLogline 84-85 of the file auth-util.go. Due to that even if you set the options.Debug to false it keeps displaying logs. It's not a big issue but it can get quite annoying as this the concerned function is called quite often ;)

    bug 
    opened by Cjdcoy 2
  • Tech docs spelling/grammar

    Tech docs spelling/grammar

    Changes

    There were a few issues within the README so I added clarity and made grammatical corrections. I've gone ahead and made a pull request if you find the changes to be suitable.

    opened by JCorcho 2
  • Nice package!

    Nice package!

    Looked through the code and examples, this is a nice looking JWT package. I do have a suggestion though: rename the /src directory to /jwt so the package name is jwt. A package name of "src" is very confusing, and not idiomatic in Go. I'm looking forward to playing with this.

    opened by bketelsen 1
  • validateCsrfStringAgainstCredentials() panic

    validateCsrfStringAgainstCredentials() panic

    ERROR http: panic serving 127.0.0.1:49244: runtime error: invalid memory address or nil pointer dereference

    echo: http: panic serving 127.0.0.1:49244: runtime error: invalid memory address or nil pointer dereference goroutine 16 [running]: net/http.(*conn).serve.func1(0xc4201ae500) /usr/lib/go-1.8/src/net/http/server.go:1721 +0xd0 panic(0x897be0, 0xb59280) /usr/lib/go-1.8/src/runtime/panic.go:489 +0x2cf /adam-hanna/jwt-auth/jwt.(*credentials).validateCsrfStringAgainstCredentials(0xc4201736d0, 0x1bf08eb000) /adam-hanna/jwt-auth/jwt/credentials.go:93 +0x3e /adam-hanna/jwt-auth/jwt.(*credentials).validateAndUpdateCredentials(0xc4201736d0, 0xc420326000) /adam-hanna/jwt-auth/jwt/credentials.go:162 +0x43 /adam-hanna/jwt-auth/jwt.(*Auth).Process(0xc4202020f0, 0xb32e60, 0xc420173630, 0xc420326000, 0x8d43e0) /adam-hanna/jwt-auth/jwt/auth.go:337 +0x249 /adam-hanna/jwt-auth/jwt.(*Auth).Handler.func1(0xb32e60, 0xc420173630, 0xc420326000) /adam-hanna/jwt-auth/jwt/auth.go:275 +0x7a net/http.HandlerFunc.ServeHTTP(0xc4201b0880, 0xb32e60, 0xc420173630, 0xc420326000) /usr/lib/go-1.8/src/net/http/server.go:1942 +0x44 /vendor/github.com/labstack/echo.WrapMiddleware.func1.1(0xb3a3c0, 0xc42014f570, 0x20, 0x8c4b80) /vendor/github.com/labstack/echo/echo.go:694 +0x174 /vendor/github.com/labstack/echo.(*Echo).Add.func1(0xb3a3c0, 0xc42014f570, 0xc420173630, 0xb334a0) /vendor/github.com/labstack/echo/echo.go:477 +0x90 /vendor/github.com/labstack/echo/middleware.GzipWithConfig.func1.1(0xb3a3c0, 0xc42014f570, 0x0, 0x0) /vendor/github.com/labstack/echo/middleware/compress.go:92 +0x173 /vendor/github.com/labstack/echo/middleware.CORSWithConfig.func1.1(0xb3a3c0, 0xc42014f570, 0xf, 0x91aff1) /vendor/github.com/labstack/echo/middleware/cors.go:113 +0x2e7 /vendor/github.com/labstack/echo/middleware.SecureWithConfig.func1.1(0xb3a3c0, 0xc42014f570, 0xb658e0, 0xc420057b18) /vendor/github.com/labstack/echo/middleware/secure.go:113 +0x2af /vendor/github.com/labstack/echo/middleware.LoggerWithConfig.func2.1(0xb3a3c0, 0xc42014f570, 0x0, 0x0) /vendor/github.com/labstack/echo/middleware/logger.go:111 +0x12b ... /vendor/github.com/labstack/echo.(*Echo).ServeHTTP.func1(0xb3a3c0, 0xc42014f570, 0xc420198ef8, 0x914a60) /vendor/github.com/labstack/echo/echo.go:574 +0x10e /vendor/github.com/labstack/echo.(*Echo).ServeHTTP(0xc420198ea0, 0xb334a0, 0xc4201550a0, 0xc420326000) /vendor/github.com/labstack/echo/echo.go:583 +0x24d net/http.serverHandler.ServeHTTP(0xc4201b60b0, 0xb334a0, 0xc4201550a0, 0xc420326000) /usr/lib/go-1.8/src/net/http/server.go:2568 +0x92 net/http.(*conn).serve(0xc4201ae500, 0xb33f20, 0xc4201aa900) /usr/lib/go-1.8/src/net/http/server.go:1825 +0x612 created by net/http.(*Server).Serve /usr/lib/go-1.8/src/net/http/server.go:2668 +0x2ce

    REQUEST HEADER X-Auth-Token : null X-Refresh-Token : null X-Csrf-Token : null

    PANIC credentials.go:92 func (c *credentials) validateCsrfStringAgainstCredentials() *jwtError { authTokenClaims, ok := c.AuthToken.Token.Claims.(*ClaimsType) <<< PANIC! ( c.AuthToken.Token is nil )

    c.AuthToken.Token is nil c.RefreshToken.Token is nil

    MY BUGFIX jwtToken.go:42

    if token == nil {
    	token = new(jwtGo.Token)
    	token.Claims = new(ClaimsType)
    	c.myLog("token is nil, set empty token (parse error=" + err.Error() + ")")
    }
    
    opened by dooglegh 1
  • Tokens in Context

    Tokens in Context

    It would be useful to have AuthToken, RefreshToken, X-Csrf-Token and expiration in the request.Context(). This is useful if you need to send tokens in request body or do something else with tokens

        authTokenString := jwtauth.GetAuthTokenFromContext(r.Context())
        refreshTokenString := jwtauth.GetRefreshTokenFromContext(r.Context())
        csrfTokenString := jwtauth.GetCSRFTokenFromContext(r.Context())
    
        // do stuffs with tokens
    
    opened by areYouLazy 1
  • Invalidation of cookies does not work

    Invalidation of cookies does not work

    Hi there

    In the NullifyTokens() func you want to delete / invalidate the authCookie and refreshCookie. Unfortunately this does not work if the cookie has no value for the path attribute. The browsers ignores the Set-Cookie headers and the cookies are preserved.

    Kind Regards

    opened by nItroFreeZer 1
  • Nil pointer reference, if refreshtoken is expired or not sent with request

    Nil pointer reference, if refreshtoken is expired or not sent with request

    Hello there

    Although this is a quite unlikely scenario, the auth.Handler will panic, caused by line 412 in auth.go, if the refresh token is not sent with the request.

    Maybe error branching after calling err := auth.Process() instead of just checking for not err != nil would be a viable solution?

    Kind Regards

    opened by iwyg 2
Releases(v1.2.0)
Owner
Adam Hanna
An entrepreneur living and working in Los Angeles. My RSA fingerprint: 3D33 EE0E 8620 44EC F7FA 3CA0 2687 062E 2A4E 0E15
Adam Hanna
The easiest JWT library to GO

JWT Go The easiest JWT Library that could be a starting point for your project. Installation go get github.com/supanadit/jwt-go Quick Start package ma

Supan Adit Pratama 16 Apr 21, 2021
A go implementation of JSON Web Tokens

jwt-go A go (or 'golang' for search engine friendliness) implementation of JSON Web Tokens NEW VERSION COMING: There have been a lot of improvements s

null 941 Sep 23, 2021
JWT login microservice with plugable backends such as OAuth2, Google, Github, htpasswd, osiam, ..

loginsrv loginsrv is a standalone minimalistic login server providing a JWT login for multiple login backends. ** Attention: Update to v1.3.0 for Goog

tarent 1.8k Sep 23, 2021
Golang implementation of JSON Web Tokens (JWT)

jwt-go A go (or 'golang' for search engine friendliness) implementation of JSON Web Tokens NEW VERSION COMING: There have been a lot of improvements s

Dave Grijalva 9.9k Sep 24, 2021
simple-jwt-provider - Simple and lightweight provider which exhibits JWTs, supports login, password-reset (via mail) and user management.

Simple and lightweight JWT-Provider written in go (golang). It exhibits JWT for the in postgres persisted user, which can be managed via api. Also, a password-reset flow via mail verification is available. User specific custom-claims also available for jwt-generation and mail rendering.

Max 20 Aug 2, 2021
JSON Web Token library

About … a JSON Web Token (JWT) library for the Go programming language. Feature complete Full test coverage Dependency free Key management The API enf

Pascal S. de Kloe 269 Sep 26, 2021
Safe, simple and fast JSON Web Tokens for Go

jwt JSON Web Token for Go RFC 7519, also see jwt.io for more. The latest version is v3. Rationale There are many JWT libraries, but many of them are h

cristaltech 289 Sep 24, 2021
This is an implementation of JWT in golang!

jwt This is a minimal implementation of JWT designed with simplicity in mind. What is JWT? Jwt is a signed JSON object used for claims based authentic

John Rowley 92 Aug 25, 2021
The boss of http auth.

Authboss Authboss is a modular authentication system for the web. It has several modules that represent authentication and authorization features that

Volatile Technologies Inc. 2.8k Sep 14, 2021
Platform-Agnostic Security Tokens implementation in GO (Golang)

Golang implementation of PASETO: Platform-Agnostic Security Tokens This is a 100% compatible pure Go (Golang) implementation of PASETO tokens. PASETO

Oleg Lobanov 538 Sep 20, 2021
A collection of authentication Go packages related to OIDC, JWKs and Distributed Claims.

cap (collection of authentication packages) provides a collection of related packages which enable support for OIDC, JWT Verification and Distributed Claims.

HashiCorp 297 Sep 19, 2021
OAuth 2.0 middleware service for chi (ported from gin by community member)

oauth middleware OAuth 2.0 Authorization Server & Authorization Middleware for go-chi This library was ported to go-chi from https://github.com/maxzer

go-chi 9 Sep 23, 2021
A standalone, specification-compliant, OAuth2 server written in Golang.

Go OAuth2 Server This service implements OAuth 2.0 specification. Excerpts from the specification are included in this README file to describe differe

Richard Knop 1.8k Sep 16, 2021
SSH Manager - manage authorized_keys file on remote servers

SSH Manager - manage authorized_key file on remote servers This is a simple tool that I came up after having to on-boarding and off-boarding developer

Sam Ban 11 Sep 19, 2021
Simple JWT Golang

sjwt Simple JSON Web Token - Uses HMAC SHA-256 Example // Set Claims claims := New() claims.Set("username", "billymister") claims.Set("account_id", 86

Brian Voelker 93 Aug 25, 2021
:closed_lock_with_key: Middleware for keeping track of users, login states and permissions

Permissions2 Middleware for keeping track of users, login states and permissions. Online API Documentation godoc.org Features and limitations Uses sec

Alexander F. Rødseth 435 Sep 6, 2021
Golang Mongodb Jwt Auth Example Using Echo

Golang Mongodb Jwt Auth Example Using Echo Golang Mongodb Rest Api Example Using Echo Prerequisites Golang 1.16.x Docker 19.03+ Docker Compose 1.25+ I

Şuayb Şimşek 5 Jun 24, 2021
an SSO and OAuth / OIDC login solution for Nginx using the auth_request module

Vouch Proxy An SSO solution for Nginx using the auth_request module. Vouch Proxy can protect all of your websites at once. Vouch Proxy supports many O

Vouch 1.5k Sep 21, 2021
Golang implementation of JWT and Refresh Token

Fiber and JWT with Refresh Token Repo ini adalah demostrasi JWT support refresh token tanpa menggunakan storage Branch Main: unlimited refresh token R

Muhamad Surya Iksanudin 5 Jul 18, 2021