├── .gitignore
├── go.mod
├── .travis.yml
├── signing.go
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── echo.go
├── gin.go
├── web_framework.go
├── LICENSE
├── authorization.go
├── jwt.go
├── custom.go
├── CODE_OF_CONDUCT.md
├── go.sum
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/supanadit/jwt-go
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible
7 | github.com/gin-gonic/gin v1.6.2
8 | github.com/labstack/echo/v4 v4.1.16
9 | github.com/mitchellh/mapstructure v1.2.2
10 | golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
11 | )
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | matrix:
4 | fast_finish: true
5 | include:
6 | - go: 1.14.x
7 | - go: master
8 |
9 | git:
10 | depth: 10
11 |
12 | before_install:
13 | - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
14 |
15 | install:
16 | - if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
17 | - if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
18 | - if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
19 |
20 | go_import_path: github.com/supanadit/jwt-go
21 |
22 | after_success:
23 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/signing.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "github.com/dgrijalva/jwt-go"
5 | )
6 |
7 | // SigningHMAC is type of signing that can be used for signing and validation JWT
8 | type SigningHMAC struct {
9 | Method *jwt.SigningMethodHMAC
10 | }
11 |
12 | // HS256 is type of SigningHMAC method
13 | func HS256() SigningHMAC {
14 | return SigningHMAC{Method: jwt.SigningMethodHS256}
15 | }
16 |
17 | // HS384 is type of SigningHMAC method
18 | func HS384() SigningHMAC {
19 | return SigningHMAC{Method: jwt.SigningMethodHS384}
20 | }
21 |
22 | // HS512 is type of SigningHMAC method
23 | func HS512() SigningHMAC {
24 | return SigningHMAC{Method: jwt.SigningMethodHS512}
25 | }
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/echo.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "github.com/labstack/echo/v4"
5 | )
6 |
7 | // GetJWTFromEchoHeader get JWT from header which provided by echo web framework
8 | func GetJWTFromEchoHeader(c echo.Context) (token string, err error) {
9 | return GetJWTFromHeader(c.Request().Header.Get("Authorization"))
10 | }
11 |
12 | // VerifyEchoHeader only verify echo header
13 | func VerifyEchoHeader(c echo.Context) (string, bool, error) {
14 | return VerifyAndBindingEchoHeader(nil, c)
15 | }
16 |
17 | // VerifyAndBindingEchoHeader verify and binding the jwt model
18 | func VerifyAndBindingEchoHeader(model interface{}, c echo.Context) (token string, isValid bool, err error) {
19 | token, err = GetJWTFromEchoHeader(c)
20 | isValid, err = VerifyAndBinding(&model, token)
21 | return token, isValid, err
22 | }
23 |
--------------------------------------------------------------------------------
/gin.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | // GetJWTFromGinHeader is to get JWT from header which provided by gin web framework
8 | func GetJWTFromGinHeader(c *gin.Context) (token string, err error) {
9 | return GetJWTFromHeader(c.GetHeader("Authorization"))
10 | }
11 |
12 | // VerifyGinHeader is the function that only verify gin header
13 | func VerifyGinHeader(c *gin.Context) (string, bool, error) {
14 | return VerifyAndBindingGinHeader(nil, c)
15 | }
16 |
17 | // VerifyAndBindingGinHeader is to verify and binding the jwt model
18 | func VerifyAndBindingGinHeader(model interface{}, c *gin.Context) (token string, isValid bool, err error) {
19 | token, err = GetJWTFromGinHeader(c)
20 | isValid, err = VerifyAndBinding(&model, token)
21 | return token, isValid, err
22 | }
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/web_framework.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "errors"
5 | "strings"
6 | )
7 |
8 | // GetJWTFromHeader get JWT from header which provided by any of web framework, but with rules JWT "token"
9 | func GetJWTFromHeader(header string) (token string, err error) {
10 | if header != "" {
11 | splitAuthorization := strings.Split(header, " ")
12 | if len(splitAuthorization) != 0 && len(splitAuthorization) == 2 {
13 | if splitAuthorization[0] != "JWT" {
14 | err = errors.New("unknown authorization type")
15 | } else {
16 | token = splitAuthorization[1]
17 | }
18 | } else {
19 | err = errors.New("invalid authorization header")
20 | }
21 | } else {
22 | err = errors.New("no authorization provided")
23 | }
24 | return token, err
25 | }
26 |
27 | // VerifyAndBinding is to verify and binding any given token
28 | func VerifyAndBinding(model interface{}, t string) (bool, error) {
29 | isValid, err := VerifyAndBindingJWT(&model, t)
30 | if err != nil {
31 | if !IsUseAuthorization() {
32 | err = nil
33 | isValid = !IsUseAuthorization()
34 | }
35 | }
36 | return isValid, err
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Supan Adit Pratama
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/authorization.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | // Authorization is the default authorization model
4 | type Authorization struct {
5 | Username string `form:"username" json:"username" xml:"username" binding:"required"`
6 | Password string `form:"password" json:"password" xml:"password" binding:"required"`
7 | }
8 |
9 | // GenerateJWT is to generate JWT token by authorization model
10 | func (auth Authorization) GenerateJWT() (string, error) {
11 | return GenerateJWT(auth)
12 | }
13 |
14 | // GenerateJWTAndSetExpiredTime generate JWT token by authorization model also set the expired time manually
15 | func (auth Authorization) GenerateJWTAndSetExpiredTime(hour int64, minute int64, seconds int64) (string, error) {
16 | return GenerateJWTAndSetExpiredTime(auth, hour, minute, seconds)
17 | }
18 |
19 | // GetPasswordEncryption is to create password encryption using bcrypt
20 | func (auth Authorization) GetPasswordEncryption() ([]byte, error) {
21 | return EncryptPassword(auth.Password)
22 | }
23 |
24 | // GetStringPasswordEncryption is to create password encryption using bcrypt and string as the result
25 | func (auth Authorization) GetStringPasswordEncryption() (string, error) {
26 | encryption, err := auth.GetPasswordEncryption()
27 | return string(encryption), err
28 | }
29 |
30 | // VerifyJWT is the simply way to check authorization
31 | func (auth Authorization) VerifyJWT(token string) (bool, error) {
32 | return VerifyJWT(token)
33 | }
34 |
35 | // VerifyPassword is the fastest way to verify password
36 | func (auth Authorization) VerifyPassword(password string) (bool, error) {
37 | ep, err := auth.GetStringPasswordEncryption()
38 | if err != nil {
39 | return false, err
40 | }
41 | return VerifyPassword(ep, password)
42 | }
43 |
44 | // VerifyEncryptedPassword is the fastest way to verify encrypted password stored in database
45 | func (auth Authorization) VerifyEncryptedPassword(password string) (bool, error) {
46 | return VerifyPassword(auth.Password, password)
47 | }
48 |
--------------------------------------------------------------------------------
/jwt.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | // secretCodeJWT is the global variable for default secret code
4 | var secretCodeJWT = "54A3E4F19C28CCA4A27E5648871A6"
5 |
6 | // useAuthorization is the variable for enable and disable authorization
7 | var useAuthorization = true
8 |
9 | // expiredHoursTime is the hours time for duration JWT token
10 | var expiredHoursTime int64 = 1
11 |
12 | // expiredMinutesTime is the minutes time for duration JWT token
13 | var expiredMinutesTime int64 = 59
14 |
15 | // expiredSecondsTime is the seconds time for duration JWT token
16 | var expiredSecondsTime int64 = 60
17 |
18 | // signingHMACMethod is a method for signing and validation JWT
19 | var signingHMACMethod SigningHMAC = HS256()
20 |
21 | // GetStringJWTSecretCode is to get JWT secret code as a string
22 | func GetStringJWTSecretCode() string {
23 | return secretCodeJWT
24 | }
25 |
26 | // GetJWTSecretCode get JWT secret code as a byte
27 | func GetJWTSecretCode() []byte {
28 | return []byte(secretCodeJWT)
29 | }
30 |
31 | // SetJWTSecretCode is to set JWT secret code globally
32 | func SetJWTSecretCode(secretCode string) {
33 | secretCodeJWT = secretCode
34 | }
35 |
36 | // IsUseAuthorization is to get status whether use authorization or not
37 | func IsUseAuthorization() bool {
38 | return useAuthorization
39 | }
40 |
41 | // EnableAuthorization is to enable authorization
42 | func EnableAuthorization() {
43 | useAuthorization = true
44 | }
45 |
46 | // DisableAuthorization is to Disable the authorization
47 | func DisableAuthorization() {
48 | useAuthorization = false
49 | }
50 |
51 | // SetExpiredTime is to set expired time for JWT session
52 | func SetExpiredTime(hour int64, minute int64, second int64) {
53 | expiredHoursTime = hour
54 | expiredMinutesTime = minute
55 | expiredSecondsTime = second
56 | }
57 |
58 | // SetHMACSigningMethod is to set signing method globally
59 | func SetHMACSigningMethod(s SigningHMAC) {
60 | signingHMACMethod = s
61 | }
62 |
63 | // GetHMACSigningMethod is to get signing method
64 | func GetHMACSigningMethod() SigningHMAC {
65 | return signingHMACMethod
66 | }
67 |
--------------------------------------------------------------------------------
/custom.go:
--------------------------------------------------------------------------------
1 | package jwt
2 |
3 | import (
4 | "errors"
5 | "github.com/dgrijalva/jwt-go"
6 | "github.com/mitchellh/mapstructure"
7 | "golang.org/x/crypto/bcrypt"
8 | "time"
9 | )
10 |
11 | // CustomClaims is the model provided by this library
12 | type CustomClaims struct {
13 | Object interface{}
14 | jwt.StandardClaims
15 | }
16 |
17 | // GenerateJWT is the function for generate JWT token
18 | func GenerateJWT(model interface{}) (s string, e error) {
19 | return GenerateJWTAndSetExpiredTime(model, expiredHoursTime, expiredMinutesTime, expiredSecondsTime)
20 | }
21 |
22 | // GenerateJWTAndSetExpiredTime will generate JWT token alongside with custom expired time
23 | func GenerateJWTAndSetExpiredTime(model interface{}, hours int64, minutes int64, seconds int64) (s string, e error) {
24 | if hours != 0 || minutes != 0 || seconds != 0 {
25 | r := CustomClaims{
26 | Object: model,
27 | StandardClaims: jwt.StandardClaims{
28 | ExpiresAt: time.Now().Local().Add(time.Hour*time.Duration(hours) +
29 | time.Minute*time.Duration(minutes) +
30 | time.Second*time.Duration(seconds)).Unix(),
31 | },
32 | }
33 | t := jwt.NewWithClaims(GetHMACSigningMethod().Method, r)
34 | s, e = t.SignedString(GetJWTSecretCode())
35 | } else {
36 | e = errors.New("expired time must be at least 1 second")
37 | }
38 | return s, e
39 | }
40 |
41 | // VerifyJWT is the function for verify any generated JWT token
42 | func VerifyJWT(token string) (bool, error) {
43 | return VerifyAndBindingJWT(nil, token)
44 | }
45 |
46 | // VerifyAndBindingJWT is the easy way to verify and binding JWT token at the same time
47 | func VerifyAndBindingJWT(model interface{}, token string) (bool, error) {
48 | isValid := !IsUseAuthorization()
49 | t, err := jwt.ParseWithClaims(token, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
50 | return GetJWTSecretCode(), nil
51 | })
52 | if t != nil {
53 | if claims, ok := t.Claims.(*CustomClaims); ok && t.Valid {
54 | if model != nil {
55 | err = mapstructure.Decode(claims.Object, &model)
56 | }
57 | isValid = true
58 | }
59 | }
60 | return isValid, err
61 | }
62 |
63 | // EncryptPassword is the function provided to encrypt any password safely
64 | func EncryptPassword(password string) ([]byte, error) {
65 | return bcrypt.GenerateFromPassword([]byte(password), 12)
66 | }
67 |
68 | // VerifyPassword is the function for verify between encryption password and requested password
69 | func VerifyPassword(encryptedPassword string, password string) (bool, error) {
70 | isValid := false
71 | err := bcrypt.CompareHashAndPassword([]byte(encryptedPassword), []byte(password))
72 | if err == nil {
73 | isValid = true
74 | }
75 | return isValid, err
76 | }
77 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at supanadit@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
5 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
6 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
7 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
8 | github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM=
9 | github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
10 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
11 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
12 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
13 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
14 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
15 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
16 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
17 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
18 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
19 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
20 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
21 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
22 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
23 | github.com/labstack/echo/v4 v4.1.16 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o=
24 | github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
25 | github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
26 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
27 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
28 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
29 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
30 | github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
31 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
32 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
33 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
34 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
35 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
36 | github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
37 | github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
38 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
39 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
40 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
41 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
42 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
43 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
44 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
45 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
46 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
47 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
48 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
49 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
50 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
51 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
52 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
53 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
54 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
55 | github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
56 | github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
57 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
58 | golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
59 | golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
60 | golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
61 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
62 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
63 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
64 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
65 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
66 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
67 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
68 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
69 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
70 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
71 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
72 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
73 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
74 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
75 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
76 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
77 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
78 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
79 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
80 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JWT Go
2 |
3 | [](https://travis-ci.org/supanadit/jwt-go)
4 | [](https://goreportcard.com/report/github.com/supanadit/jwt-go)
5 | [](https://godoc.org/github.com/supanadit/jwt-go)
6 |
7 | The easiest JWT Library that could be a starting point for your project.
8 |
9 | ## Installation
10 |
11 | `go get github.com/supanadit/jwt-go`
12 |
13 | ## Quick Start
14 |
15 | ```go
16 | package main
17 |
18 | import (
19 | "fmt"
20 | "github.com/supanadit/jwt-go"
21 | "log"
22 | )
23 |
24 | func main() {
25 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
26 | jwt.SetJWTSecretCode("Your Secret Code")
27 |
28 | // Create default authorization
29 | auth := jwt.Authorization{
30 | Username: "admin",
31 | Password: "admin",
32 | }
33 |
34 | // Generate JWT Token from default authorization model
35 | token, err := auth.GenerateJWT()
36 | if err != nil {
37 | log.Fatal(err)
38 | }
39 |
40 | fmt.Println("JWT Token : " + token)
41 |
42 | // Verify the token
43 | valid, err := auth.VerifyJWT(token)
44 | if err != nil {
45 | fmt.Println(err)
46 | }
47 |
48 | fmt.Print("Status : ")
49 |
50 | if valid {
51 | fmt.Println("Valid")
52 | } else {
53 | fmt.Println("Invalid")
54 | }
55 | }
56 | ```
57 |
58 | Custom Authorization
59 |
60 |
61 |
62 | ```go
63 | package main
64 |
65 | import (
66 | "fmt"
67 | "github.com/supanadit/jwt-go"
68 | "log"
69 | )
70 |
71 | type Login struct {
72 | Email string
73 | Password string
74 | Name string
75 | }
76 |
77 | func main() {
78 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
79 | jwt.SetJWTSecretCode("Your Secret Code")
80 |
81 | // Create default authorization
82 | auth := Login{
83 | Email: "asd@asd.com",
84 | Password: "asd",
85 | Name: "asd",
86 | }
87 |
88 | // Generate JWT Token from default authorization model
89 | token, err := jwt.GenerateJWT(auth)
90 | if err != nil {
91 | log.Fatal(err)
92 | }
93 |
94 | fmt.Println("JWT Token : " + token)
95 |
96 | // Variable for decoded JWT token
97 | var dataAuth Login
98 | // Verify the token
99 | valid, err := jwt.VerifyAndBindingJWT(&dataAuth, token)
100 | if err != nil {
101 | fmt.Println(err)
102 | }
103 |
104 | // or simply you can do this, if you don't need to decode the JWT
105 | // valid, err := jwt.VerifyJWT(token)
106 | // if err != nil {
107 | // fmt.Println(err)
108 | // }
109 |
110 | fmt.Print("Status : ")
111 |
112 | if valid {
113 | fmt.Println("Valid")
114 | } else {
115 | fmt.Println("Invalid")
116 | }
117 | }
118 | ```
119 |
120 |
121 |
122 |
123 | Encrypt & Verify Password
124 |
125 |
126 |
127 | ```go
128 | package main
129 |
130 | import (
131 | "fmt"
132 | "github.com/supanadit/jwt-go"
133 | "log"
134 | )
135 |
136 | type Login struct {
137 | Email string
138 | Password string
139 | }
140 |
141 | func main() {
142 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
143 | jwt.SetJWTSecretCode("Your Secret Code")
144 |
145 | // Create authorization from your own struct
146 | auth := Login{
147 | Email: "example@email.com",
148 | Password: "123",
149 | }
150 |
151 | // Encrypt password, which you can save to database
152 | ep, err := jwt.EncryptPassword(auth.Password)
153 | if err != nil {
154 | log.Fatal(err)
155 | }
156 |
157 | fmt.Println("Encrypted Password " + string(ep))
158 |
159 | // Verify Encrypted Password
160 | valid, err := jwt.VerifyPassword(string(ep), auth.Password)
161 | if err != nil {
162 | fmt.Println(err)
163 | }
164 |
165 | fmt.Print("Status : ")
166 |
167 | if valid {
168 | fmt.Println("Valid")
169 | } else {
170 | fmt.Println("Invalid")
171 | }
172 | }
173 | ```
174 |
175 |
176 |
177 |
178 | Decrypt Password
179 |
180 |
181 | No you can't, as the thread at [Stack Exchange](https://security.stackexchange.com/questions/193943/is-it-possible-to-decrypt-bcrypt-encryption)
182 |
183 | > bcrypt is not an encryption function, it's a password hashing function, relying on Blowfish's key scheduling, not its encryption. Hashing are mathematical one-way functions, meaning there is no way to reverse the output string to get the input string.
184 |
of course only Siths deal in absolutes and there are a few attacks against hashes. But none of them are "reversing" the hashing, AFAIK.
185 |
186 | so that enough to secure the password
187 |
188 |
189 |
190 |
191 | Set Expired Time
192 |
193 |
194 | ```go
195 | package main
196 |
197 | import (
198 | "fmt"
199 | "github.com/supanadit/jwt-go"
200 | "log"
201 | )
202 |
203 | func main() {
204 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
205 | jwt.SetJWTSecretCode("Your Secret Code")
206 |
207 | // You can simply do this, jwt.setExpiredTime(Hour,Minute,Second)
208 | jwt.SetExpiredTime(0, 0, 1)
209 | }
210 | ```
211 |
212 |
213 |
214 |
215 | Support Gin Web Framework
216 |
217 |
218 | ```go
219 | package main
220 |
221 | import (
222 | "github.com/gin-gonic/gin"
223 | "github.com/supanadit/jwt-go"
224 | "net/http"
225 | )
226 |
227 | func main() {
228 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
229 | jwt.SetJWTSecretCode("Your Secret Code")
230 |
231 | // Create authorization
232 | auth := jwt.Authorization{
233 | Username: "admin",
234 | Password: "123",
235 | }
236 |
237 | router := gin.Default()
238 |
239 | // Login / Authorization for create JWT Token
240 | router.POST("/auth", func(c *gin.Context) {
241 | var a jwt.Authorization
242 | err := c.Bind(&a)
243 | if err != nil {
244 | c.JSON(http.StatusBadRequest, gin.H{
245 | "status": "Invalid body request",
246 | "token": nil,
247 | })
248 | } else {
249 | valid, err := auth.VerifyPassword(a.Password)
250 | if err != nil {
251 | c.JSON(http.StatusBadRequest, gin.H{
252 | "status": "Wrong username or password",
253 | "token": nil,
254 | })
255 | } else {
256 | if valid {
257 | token, err := a.GenerateJWT()
258 | if err != nil {
259 | c.JSON(http.StatusInternalServerError, gin.H{
260 | "status": "Can't generate JWT token",
261 | "token": nil,
262 | })
263 | } else {
264 | c.JSON(http.StatusOK, gin.H{
265 | "status": "Success",
266 | "token": token,
267 | })
268 | }
269 | } else {
270 | c.JSON(http.StatusBadRequest, gin.H{
271 | "status": "Wrong username or password",
272 | "token": nil,
273 | })
274 | }
275 | }
276 | }
277 | })
278 |
279 | // Test Authorization
280 | router.GET("/test", func(c *gin.Context) {
281 | // Variable for binding if you need decoded JWT
282 | var dataAuth jwt.Authorization
283 | // Verify and binding JWT
284 | token, valid, err := jwt.VerifyAndBindingGinHeader(&dataAuth, c)
285 |
286 | // in case if you don't want to decode the JWT, simply use this code
287 | // token, valid, err := jwt.VerifyGinHeader(c)
288 |
289 | if err != nil {
290 | c.JSON(http.StatusOK, gin.H{
291 | "status": err.Error(),
292 | })
293 | } else {
294 | if valid {
295 | c.JSON(http.StatusOK, gin.H{
296 | "status": token + " is valid",
297 | })
298 | } else {
299 | c.JSON(http.StatusBadRequest, gin.H{
300 | "status": "Invalid",
301 | })
302 | }
303 | }
304 | })
305 |
306 | _ = router.Run(":8080")
307 | }
308 | ```
309 |
310 |
311 |
312 |
313 | Support Echo Web Framework
314 |
315 |
316 | ```go
317 | package main
318 |
319 | import (
320 | "github.com/labstack/echo/v4"
321 | "github.com/supanadit/jwt-go"
322 | "net/http"
323 | )
324 |
325 | func main() {
326 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
327 | jwt.SetJWTSecretCode("Your Secret Code")
328 |
329 | // Create authorization
330 | auth := jwt.Authorization{
331 | Username: "admin",
332 | Password: "123",
333 | }
334 |
335 | e := echo.New()
336 |
337 | // Login / Authorization for create JWT Token
338 | e.POST("/auth", func(c echo.Context) error {
339 | a := new(jwt.Authorization)
340 | // Create struct for response, or you can create globally by your self
341 | var r struct {
342 | Status string
343 | Token string
344 | }
345 | err := c.Bind(a)
346 | if err != nil {
347 | r.Status = "Invalid body request"
348 | return c.JSON(http.StatusBadRequest, &r)
349 | } else {
350 | valid, err := auth.VerifyPassword(a.Password)
351 | if err != nil {
352 | r.Status = "Wrong username or password"
353 | return c.JSON(http.StatusBadRequest, &r)
354 | } else {
355 | if valid {
356 | token, err := a.GenerateJWT()
357 | if err != nil {
358 | r.Status = "Can't generate JWT Token"
359 | return c.JSON(http.StatusInternalServerError, &r)
360 | } else {
361 | r.Status = "Success"
362 | r.Token = token
363 | return c.JSON(http.StatusOK, &r)
364 | }
365 | } else {
366 | r.Status = "Wrong username or password"
367 | return c.JSON(http.StatusBadRequest, &r)
368 | }
369 | }
370 | }
371 | })
372 |
373 | // Test Authorization
374 | e.GET("/test", func(c echo.Context) error {
375 | // Create struct for response
376 | var r struct {
377 | Status string
378 | }
379 | // Variable for binding if you need decoded JWT
380 | dataAuth := new(jwt.Authorization)
381 | // Verify and binding JWT
382 | token, valid, err := jwt.VerifyAndBindingEchoHeader(&dataAuth, c)
383 |
384 | // in case if you don't want to decode the JWT, simply use this code
385 | // Token, valid, err := jwt.VerifyEchoHeader(c)
386 |
387 | if err != nil {
388 | r.Status = err.Error()
389 | return c.JSON(http.StatusBadRequest, &r)
390 | } else {
391 | if valid {
392 | r.Status = token + " is valid"
393 | return c.JSON(http.StatusOK, &r)
394 | } else {
395 | r.Status = "Invalid"
396 | return c.JSON(http.StatusBadRequest, &r)
397 | }
398 | }
399 | })
400 |
401 | // Start server
402 | e.Logger.Fatal(e.Start(":1323"))
403 | }
404 | ```
405 |
406 |
407 |
408 |
409 | Disable & Enable Authorization
410 |
411 |
412 | ```go
413 | package main
414 |
415 | import (
416 | "github.com/supanadit/jwt-go"
417 | )
418 |
419 | func main() {
420 | // Set Your JWT Secret Code, its optional but important, because default secret code is not secure
421 | jwt.SetJWTSecretCode("Your Secret Code")
422 |
423 | // Disable authorization, meaning when verify jwt token it will return true even if the token was expired or invalid
424 | jwt.DisableAuthorization()
425 |
426 | // or
427 |
428 | // Enable authorization
429 | jwt.EnableAuthorization()
430 | }
431 | ```
432 |
433 |
434 |
435 |
436 | Set HMAC Signing Method
437 |
438 |
439 | ```go
440 | package main
441 |
442 | import "github.com/supanadit/jwt-go"
443 |
444 | func main() {
445 | // Set HMAC signing method
446 | jwt.SetHMACSigningMethod(jwt.HS256()) // or jwt.HS384(), jwt.HS512()
447 | }
448 | ```
449 |
450 |
451 |
452 |
453 | ## Thanks to
454 | - [jwt-go](https://github.com/dgrijalva/jwt-go)
455 | - [bcrypt](golang.org/x/crypto/bcrypt)
456 | - [mapstructure](github.com/mitchellh/mapstructure)
457 |
--------------------------------------------------------------------------------