---
# System prepended metadata

title: Golang JWT Auth
tags: [go, Auth0]

---


###### tags: `go` `Auth0`
# Golang JWT Auth

jwt ミドルウェアを使って、jwt認証をする。


```bash=
mkdir client 
cd client
go mod init go-jwt-tutorial/client
```


# クライント側
```go=
package main

import (
	"fmt"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
)

var mySigningkey = []byte("mysupersecretphrase")

func GenerateJWT() (string, error) {
	token := jwt.New(jwt.SigningMethodHS256)
	claims := token.Claims.(jwt.MapClaims)

	claims["authorized"] = true
	claims["user"] = "Elliot Forbes"
	claims["exp"] = time.Now().Add(time.Minute * 30).Unix()

	tokenString, err := token.SignedString(mySigningkey)

	if err != nil {
		fmt.Errorf("something weng wrong: %s", err.Error())
		return "", err
	}
	return tokenString, nil
}

func main() {
	tokenString, err := GenerateJWT()
	if err != nil {
		fmt.Println("Error generating token string")
	}

	fmt.Println(tokenString)
}

```

jwtパッケージを使って、JWT文字列を生成
HMACSHA256 方式
payload
- authorized
- user
- exp : 期限

SigningKey(署名キー) の文字列が同じである限り、
同じペイロードは同じjwtになる。

署名キー(秘密鍵or共通鍵)は環境変数から読み込んで使う方式がおすすめ
```go=
var myStringKey = os.Get("MY_JWT_TOKEN")
```



# サーバー側
secretPageハンドラのレスポンスは、正しくJWT認証できなかったら見れないことにする。

```go=
package main

import "github.com/gin-gonic/gin"

func secretPage(c *gin.Context) {
	c.String(200, "super secret Information")
}

func main() {
	router := gin.Default()
	router.GET("/", secretPage)
	router.Run(":8000")
}

```
上記のAPIサーバーに、認証を追加する。

## 認証を設計する方針
ミドルウェア的発送
**isAuthorized()** を使って、クロージャーを返す。

要するに、pythonのデコレーターのように、
gin.HandleFuncを引数にしてHandleFuncを返す関数を使って、
ただのハンドラに認証の追加機能をつける

```go=
func isAuthorized(endpoint gin.HandlerFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		if c.Request.Header["Token"] != nil {

		} else {
			c.String(200, "Not Authorized")
		}
	}
}

func main() {
	router := gin.Default()
	router.GET("/", isAuthorized(secretPage))
	router.Run(":8000")
}

```

## 完成形(HMAC暗号)
```go=
var mySigningKey = []byte("mysupersecretphrase")

func secretPage(c *gin.Context) {
	c.String(200, "secret message")
}

func isAuthorized(endpoint gin.HandlerFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		if c.Request.Header["Token"] != nil {
			token, err := jwt.Parse(c.Request.Header["Token"][0], func(token *jwt.Token) (interface{}, error) {
				if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
					return nil, fmt.Errorf("there was an error")
				}
				return mySigningKey, nil
			})

			if err != nil {
				c.String(200, err.Error())
			}

			if token.Valid {
				endpoint(c)
			}

		} else {
			c.String(200, "Not Authorized")
		}
	}
}

func main() {
	router := gin.Default()
	router.GET("/", isAuthorized(secretPage))
	router.Run(":8000")
}
```

HMAC(共有鍵方式)なので、同じSigningkey(署名キー)で暗号化、復号化する。

1. リクエストヘッダーに "Token" ヘッダーがあるかどうか
    - 実際は Authorization　とか
2. もしあれば、中身のトークンを jwt.Parse()メソッドでパース
3. パースされたJWT(暗号化されたまま)をコールバックに受け取るので、復号化する?
4. token.Validというフィールドがtrueなら、実際のハンドラを実行する。


