├── README.md └── jwt.go /README.md: -------------------------------------------------------------------------------- 1 | ## Simple authentication example using JSON web tokens and Go 2 | 3 | #### How to run 4 | 5 | Simple fire it up with **go run jwt.go** and it's running on port 9000 6 | 7 | Visit **/settoken** to get a token 8 | 9 | Visit **/profile** only if you have a valid token 10 | 11 | Visit **/logout** to logout if you have a vlid token 12 | 13 | #### Uses: 14 | 15 | * [dgrijalva/jwt-go](https://github.com/dgrijalva/jwt-go) 16 | 17 | -------------------------------------------------------------------------------- /jwt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/dgrijalva/jwt-go" 10 | ) 11 | 12 | type Key int 13 | 14 | const MyKey Key = 0 15 | 16 | // JWT schema of the data it will store 17 | type Claims struct { 18 | Username string `json:"username"` 19 | jwt.StandardClaims 20 | } 21 | 22 | // create a JWT and put in the clients cookie 23 | func setToken(res http.ResponseWriter, req *http.Request) { 24 | expireToken := time.Now().Add(time.Hour * 1).Unix() 25 | expireCookie := time.Now().Add(time.Hour * 1) 26 | 27 | claims := Claims{ 28 | "myusername", 29 | jwt.StandardClaims{ 30 | ExpiresAt: expireToken, 31 | Issuer: "localhost:9000", 32 | }, 33 | } 34 | 35 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 36 | 37 | signedToken, _ := token.SignedString([]byte("secret")) 38 | 39 | cookie := http.Cookie{Name: "Auth", Value: signedToken, Expires: expireCookie, HttpOnly: true} 40 | http.SetCookie(res, &cookie) 41 | 42 | http.Redirect(res, req, "/profile", 307) 43 | } 44 | 45 | // middleware to protect private pages 46 | func validate(page http.HandlerFunc) http.HandlerFunc { 47 | return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { 48 | cookie, err := req.Cookie("Auth") 49 | if err != nil { 50 | http.NotFound(res, req) 51 | return 52 | } 53 | 54 | token, err := jwt.ParseWithClaims(cookie.Value, &Claims{}, func(token *jwt.Token) (interface{}, error) { 55 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 56 | return nil, fmt.Errorf("Unexpected signing method") 57 | } 58 | return []byte("secret"), nil 59 | }) 60 | if err != nil { 61 | http.NotFound(res, req) 62 | return 63 | } 64 | 65 | if claims, ok := token.Claims.(*Claims); ok && token.Valid { 66 | ctx := context.WithValue(req.Context(), MyKey, *claims) 67 | page(res, req.WithContext(ctx)) 68 | } else { 69 | http.NotFound(res, req) 70 | return 71 | } 72 | }) 73 | } 74 | 75 | // only viewable if the client has a valid token 76 | func protectedProfile(res http.ResponseWriter, req *http.Request) { 77 | claims, ok := req.Context().Value(MyKey).(Claims) 78 | if !ok { 79 | http.NotFound(res, req) 80 | return 81 | } 82 | 83 | fmt.Fprintf(res, "Hello %s", claims.Username) 84 | } 85 | 86 | // deletes the cookie 87 | func logout(res http.ResponseWriter, req *http.Request) { 88 | deleteCookie := http.Cookie{Name: "Auth", Value: "none", Expires: time.Now()} 89 | http.SetCookie(res, &deleteCookie) 90 | return 91 | } 92 | 93 | func main() { 94 | http.HandleFunc("/settoken", setToken) 95 | http.HandleFunc("/profile", validate(protectedProfile)) 96 | http.HandleFunc("/logout", validate(logout)) 97 | http.ListenAndServe(":9000", nil) 98 | } 99 | --------------------------------------------------------------------------------