• Stars
    star
    2,545
  • Rank 18,029 (Top 0.4 %)
  • Language
    Go
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

JWT Middleware for Gin framework

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"

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.",
  })
}

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

func main() {
  port := os.Getenv("PORT")
  r := gin.Default()

  if port == "" {
    port = "8000"
  }

  // the jwt middleware
  authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
    Realm:       "test zone",
    Key:         []byte("secret key"),
    Timeout:     time.Hour,
    MaxRefresh:  time.Hour,
    IdentityKey: identityKey,
    PayloadFunc: func(data interface{}) jwt.MapClaims {
      if v, ok := data.(*User); ok {
        return jwt.MapClaims{
          identityKey: v.UserName,
        }
      }
      return jwt.MapClaims{}
    },
    IdentityHandler: func(c *gin.Context) interface{} {
      claims := jwt.ExtractClaims(c)
      return &User{
        UserName: claims[identityKey].(string),
      }
    },
    Authenticator: 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
    },
    Authorizator: func(data interface{}, c *gin.Context) bool {
      if v, ok := data.(*User); ok && v.UserName == "admin" {
        return true
      }

      return false
    },
    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>"
    // - "param:<name>"
    TokenLookup: "header: Authorization, query: token, cookie: jwt",
    // TokenLookup: "query:token",
    // TokenLookup: "cookie:token",

    // TokenHeadName is a string in the header. Default value is "Bearer"
    TokenHeadName: "Bearer",

    // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
    TimeFunc: time.Now,
  })

  if err != nil {
    log.Fatal("JWT Error:" + err.Error())
  }

  // When you use jwt.New(), the function is already automatically called for checking,
  // which means you don't need to call it again.
  errInit := authMiddleware.MiddlewareInit()

  if errInit != nil {
    log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
  }

  r.POST("/login", authMiddleware.LoginHandler)

  r.NoRoute(authMiddleware.MiddlewareFunc(), 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"})
  })

  auth := r.Group("/auth")
  // Refresh time can be longer than token timeout
  auth.GET("/refresh_token", authMiddleware.RefreshHandler)
  auth.Use(authMiddleware.MiddlewareFunc())
  {
    auth.GET("/hello", helloHandler)
  }

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

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.

More Repositories

1

gorush

A push notification server written in Go (Golang).
Go
7,213
star
2

ssh-action

GitHub Actions for executing remote ssh commands.
Dockerfile
3,247
star
3

scp-action

GitHub Action that copy files and artifacts via SSH.
Shell
824
star
4

telegram-action

GitHub Action that sends a Telegram message.
Dockerfile
660
star
5

react-recaptcha

A react.js reCAPTCHA for Google
JavaScript
633
star
6

CodeGPT

A CLI written in Go language that writes git commit messages or do a code review brief for you using ChatGPT AI (gpt-4, gpt-3.5-turbo model) and automatically installs a git prepare-commit-msg hook.
Go
521
star
7

gofight

Testing API Handler written in Golang.
Go
437
star
8

lambda-action

GitHub Action for Deploying Lambda code to an existing function
Go
315
star
9

easyssh-proxy

easyssh-proxy provides a simple implementation of some SSH protocol features in Go
Go
287
star
10

drone-ssh

Drone plugin for executing remote ssh commands
Go
222
star
11

go-fcm

Firebase Cloud Messaging Library for Golang
Go
212
star
12

gulp-compass

Compass plugin for gulp
JavaScript
174
star
13

golang-graphql-benchmark

benchmark of golang GraphQL framework.
Go
127
star
14

drone-scp

Copy files and artifacts via SSH using a binary, docker or Drone CI.
Go
117
star
15

CodeIgniter-reCAPTCHA

reCAPTCHA library for CodeIgniter
PHP
106
star
16

drone-on-kubernetes

Examples of how to run Drone on Kubernetes (AWS && GKE)
Shell
101
star
17

flutter-gorush

flutter demo app with gorush (push notification server)
Dart
95
star
18

docker-backup-database

Docker image to periodically backup your database (MySQL, Postgres, or MongoDB) to S3 or local disk.
Go
93
star
19

drone-telegram

Drone plugin for sending Telegram notifications
Go
89
star
20

jenkins-action

GitHub Action that trigger Jenkins job.
Dockerfile
83
star
21

CodeIgniter-Native-Session

codeigniter native session
PHP
82
star
22

nginx-image-resizer

Docker Container of real time image resizing and caching
Shell
81
star
23

html5-template-engine

html5 template engine with CoffeeScript, Compass, RequireJS.
CoffeeScript
80
star
24

drone-line

Sending line notifications using a binary, docker or Drone CI.
Go
79
star
25

discord-action

GitHub Action that sends a Discord message.
Dockerfile
76
star
26

npm-vs-yarn

npm vs yarn install speed testing.
Dockerfile
70
star
27

gin-lambda

running golang using gin framework in AWS Lambda & API Gateway
Go
65
star
28

drone-git-push

Drone plugin for deploying code using git push
Go
62
star
29

gitlab-ci-action

GitHub Action that trigger gitlab CI build.
Dockerfile
61
star
30

facebook-action

GitHub Action that sends a Facebook message.
Dockerfile
61
star
31

CodeIgniter-Log-Library

Store php error or exception logs into database.
PHP
60
star
32

macbook

Some tips and command for my MacOS.
59
star
33

CodeIgniter-Nexmo-Message

Class Nexmo Message handles the methods and properties of sending an SMS message.
PHP
48
star
34

graceful

graceful shutdown package when a service is turned off by software function
Go
48
star
35

drone-terraform-in-aws

drone infrastructure in AWS
HCL
47
star
36

Shell-Script

Shell Script on FreeBSD or Ubuntu
Shell
37
star
37

PHP-Git-Deploy

Git Deployment with PHP
PHP
36
star
38

drone-jenkins

Drone plugin for trigger Jenkins jobs.
Go
36
star
39

drone-discord

Drone plugin for sending message to Discord channel using Webhook
Go
35
star
40

CodeIgniter-App

Integrate RESTfull API, Base Model, Ion Auth module and template module
PHP
35
star
41

dotfiles

Bootstrap for your terminal on Linux or FreeBSD
Shell
33
star
42

golang-testing

Docker image includes golang coverage tools for testing.
Roff
29
star
43

codeigniter-docker

Like Laravel Homestead but for Docker with CodeIgniter Framework.
Shell
28
star
44

gh-pages-action

A GitHub Action to deploy a static site on GitHub Pages.
Shell
28
star
45

drone-lambda

Deploying Lambda code with drone CI to an existing function
Go
25
star
46

loadbalancer-algorithms

Load balancer Algorithms
Go
24
star
47

gin-status-api

Golang cpu, memory, gc, etc information api handler written in Go (Golang) for gin framework
Go
23
star
48

docker-multi-stage-build

Multi-Stage Docker Builds for Creating Tiny Go Images
Makefile
23
star
49

linkit-smart-7688-golang

Build static binary using golang for MT7688.
22
star
50

CodeIgniter-Google-URL-Shortener-API

CodeIgniter Google URL Shortener API
PHP
22
star
51

CodeIgniter-Template

A Lightweight Codeigniter Template Libray
PHP
21
star
52

codeigniter-facebook-php-sdk-v4

Intergrate facebook php sdk v4 with CodeIgniter Framewrok.
PHP
20
star
53

docker-ecr-action

Publish Docker Images to the Amazon Elastic Container Registry (ECR)
Dockerfile
19
star
54

flutter-docker

Unit testing for flutter in Docker
Dockerfile
19
star
55

com

This is an open source project for commonly used functions for the Go programming language.
Go
18
star
56

drone-gitlab-ci

Drone plugin for trigger gitlab-ci jobs.
Go
18
star
57

CodeIgniter-Gearman-Library

Gearman library for CodeIgniter PHP Framework
PHP
18
star
58

go-kkbox

KKBOX Open API SDK for Golang.
Go
17
star
59

jquery-migrate

shim repo for jQuery Migrate package
16
star
60

go-storage

storage interface for local disk or AWS S3 (or Minio) platform
Go
15
star
61

minify-tool

minify all html, css, js and optimize image files for web project.
Shell
15
star
62

drone-facebook

Drone plugin for sending Facebook notifications
Go
15
star
63

ansible-drone

Ansible role to configure drone (server and agent)
Jsonnet
15
star
64

server-configs

Linux Server Config
Nginx
14
star
65

drone-packer

drone plugin for build Automated Machine Images
Go
14
star
66

database-backup-action

GitHub Actions for periodically backup your database (MySQL, Postgres, or MongoDB) to S3 or local disk.
Roff
14
star
67

PHP-CodeIgniter-Framework-Taiwan

CodeIgniter 是一套小巧但功能强大的 PHP 框架,做為一個簡單而“優雅”的工具包,它是一套專為 PHP 開發者建立功能完善的 Web 應用程序。如果你是一個使用虛擬主機,並且為客戶所要求的期限而煩惱的開發人員,如果你已經厭倦那些難而且效率不高的框架
JavaScript
14
star
68

drone-sftp-cache

Drone plugin for caching artifacts to a central server using sftp
Go
13
star
69

jquery.slideShow

This simple slideshow plugin will provide your effect gallery
JavaScript
10
star
70

js-video-player

Integrate Dailymotion, Vimeo, Youtube API.
JavaScript
10
star
71

jquery-twzipcode

在網頁建立多組 3 碼台灣郵遞區號表單元素的 jQuery Plugin ─ 讀取快速、不需使用資料庫。
JavaScript
10
star
72

slush-html5-template

html5 template engine generator (RequireJS/CoffeeScript/Compass/jQuery/Mocha) for Slush.
CSS
10
star
73

go-spgateway

智付通金流串接
Go
9
star
74

drone-on-docker-compose

Drone running on docker-compose
9
star
75

php-i18n

PHP i18n Library
PHP
9
star
76

CodeIgniter-i18n

i18n library for CodeIgniter 2.1.x
PHP
8
star
77

go-jwt-server

JWT Token Server written in Go (Golang)
Go
8
star
78

git-hooks

Parse PHP error on php files and detect "console syntax" on javascript or coffee files before commit.
Shell
8
star
79

go-hello

hello world for go lang
Makefile
8
star
80

Codeigniter-Base-Model

CodeIgniter base CRUD model to remove repetition and increase productivity
PHP
7
star
81

livescript-gulp

A tiny wrapper around Gulp to run your gulpfile.ls.
JavaScript
7
star
82

appleboy.github.com

My Home Page
HTML
7
star
83

CodeIgniter-TextMagic-API

CodeIgniter Library for TextMagic API
PHP
7
star
84

backbone-template-engine

Backbone template engine with CoffeeScript, Compass, RequireJS.
ApacheConf
7
star
85

blog

My Chinese Blog
PHP
6
star
86

codegpt-action

GitHub Action for generating code review brief using ChatGPT AI (gpt-4, gpt-3.5-turbo model)
Shell
6
star
87

go-myallocator

Golang SDK for OTA's to easily integrate with the MyAllocator OTA BuildToUs API
Go
6
star
88

CodeIgniter-Plurk-API

A Plurk API Module for CodeIgniter
PHP
6
star
89

line-action

GitHub Action that sends a Line message.
Dockerfile
5
star
90

appleboy

5
star
91

go-mailer

send email package
Go
5
star
92

android-docker

Android Docker image
Shell
5
star
93

gin-revision-middleware

Revision middleware for Gin framework written in Go (Golang).
Go
5
star
94

sails-auth-ldap-example

Example SailsJS application with ldap authentication.
JavaScript
5
star
95

drone-minio

Drone plugin to upload or remove filesystems and object storage.
Go
5
star
96

detect

Golang library to detect the device platform given an user agent.
Go
4
star
97

laravel-elixir-cssfmt

Laravel Elixir CSSfmt Extension
JavaScript
4
star
98

golang-cli-example

CLI Example for Golang
Go
4
star
99

cacheman-promise

cacheman library with a promise interface
JavaScript
4
star
100

CodeIgniter-MY-Model

CodeIgniter base CRUD model
PHP
4
star