Skip to content

Instantly share code, notes, and snippets.

@shinofara
Created July 30, 2017 12:48
Show Gist options
  • Save shinofara/b540f50d6456951aa9ebccd71a6874a9 to your computer and use it in GitHub Desktop.
Save shinofara/b540f50d6456951aa9ebccd71a6874a9 to your computer and use it in GitHub Desktop.
auth0-go
package main
import (
"encoding/json"
// "encoding/base64"
"fmt"
"net/http"
"strings"
"bytes"
"io"
auth0 "github.com/auth0-community/go-auth0"
"github.com/gorilla/mux"
jose "gopkg.in/square/go-jose.v2"
jwt2 "gopkg.in/square/go-jose.v2/jwt"
"github.com/SermoDigital/jose/jws"
"github.com/SermoDigital/jose/crypto"
"log"
"time"
)
const JWKS_URI = "https://shinofara.auth0.com/.well-known/jwks.json"
const AUTH0_API_ISSUER = "https://shinofara.auth0.com/"
var AUTH0_API_AUDIENCE = []string{"http://localhost:8080"}
type Response struct {
Message string `json:"message"`
}
func main() {
r := mux.NewRouter()
// This route is always accessible
r.Handle("/api/public", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := Response{
Message: "Hello from a public endpoint! You don't need to be authenticated to see this.",
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
}))
// This route is only accessible if the user has a valid access_token with the read:messages scope
// We are wrapping the checkJwt middleware around the handler function which will check for a
// valid token and scope.
r.HandleFunc("/", handler)
r.Handle("/api/private", checkJwt(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := Response{
Message: "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
})))
fmt.Println("Listening on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", r))
}
//var mySigningKey = []byte("e2EkJVamyKxEPxK_QDw7f_T8kddGaFgfNM2PwRutgpghgp4ytCZsRsrgbazW-vFP")
var mySigningKey = []byte("API SECRET")
func handler(w http.ResponseWriter, r *http.Request) {
expires := time.Now().Add(time.Duration(10) * time.Second)
claims := jws.Claims{}
claims.SetExpiration(expires)
claims.SetIssuedAt(time.Now())
uid := fmt.Sprintf("%d", time.Now().Add(time.Hour * 24).Unix())
clientID := "CLIENT ID"
claims["jti"] = uid
claims["sub"] = fmt.Sprintf("%s@clients", clientID)
claims["aud"] = "http://localhost:8080"
claims["iss"] = "https://shinofara.auth0.com/"
claims["scopes"] = map[string]map[string][]string{
"users": map[string][]string{"actions": []string{"read"}},
"user_idp_tokens": map[string][]string{"actions": []string{"read"}},
}
jwt := jws.NewJWT(claims, crypto.SigningMethodHS256)
b, _ := jwt.Serialize(mySigningKey)
/* Set token claims */
//再利用を防ぐため毎回ユニークであること
// claims["admin"] = true
// claims["sub"] = fmt.Sprintf("%s@clients", clientID)
// claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
// claims["iat"] = time.Now().Unix()
/* Sign the token with our secret */
tokenString := string(b)
w.Write([]byte(tokenString))
/* Finally, write the token to the browser window */
req, err := http.NewRequest("GET", "https://shinofara.auth0.com/api/v2/users", nil)
if err != nil {
log.Fatal(err)
}
// tokenString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJqSTJOekpHTjBKQ09VTkJPRVF5UXpaRlJUWTFNall3TjBRNFFUazFRVFF4TnpKQ05qbEVPUSJ9.eyJpc3MiOiJodHRwczovL3NoaW5vZmFyYS5hdXRoMC5jb20vIiwic3ViIjoibVh0MzMyUkI1bHhwUXN6dkNDc24yZjRzZXRzMXNFUlRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vc2hpbm9mYXJhLmF1dGgwLmNvbS9hcGkvdjIvIiwiZXhwIjoxNTAxMjM0MDk5LCJpYXQiOjE1MDEyMjY4OTksInNjb3BlIjoicmVhZDpjbGllbnRfZ3JhbnRzIGNyZWF0ZTpjbGllbnRfZ3JhbnRzIGRlbGV0ZTpjbGllbnRfZ3JhbnRzIHVwZGF0ZTpjbGllbnRfZ3JhbnRzIHJlYWQ6dXNlcnMgdXBkYXRlOnVzZXJzIGRlbGV0ZTp1c2VycyBjcmVhdGU6dXNlcnMgcmVhZDp1c2Vyc19hcHBfbWV0YWRhdGEgdXBkYXRlOnVzZXJzX2FwcF9tZXRhZGF0YSBkZWxldGU6dXNlcnNfYXBwX21ldGFkYXRhIGNyZWF0ZTp1c2Vyc19hcHBfbWV0YWRhdGEgY3JlYXRlOnVzZXJfdGlja2V0cyByZWFkOmNsaWVudHMgdXBkYXRlOmNsaWVudHMgZGVsZXRlOmNsaWVudHMgY3JlYXRlOmNsaWVudHMgcmVhZDpjbGllbnRfa2V5cyB1cGRhdGU6Y2xpZW50X2tleXMgZGVsZXRlOmNsaWVudF9rZXlzIGNyZWF0ZTpjbGllbnRfa2V5cyByZWFkOmNvbm5lY3Rpb25zIHVwZGF0ZTpjb25uZWN0aW9ucyBkZWxldGU6Y29ubmVjdGlvbnMgY3JlYXRlOmNvbm5lY3Rpb25zIHJlYWQ6cmVzb3VyY2Vfc2VydmVycyB1cGRhdGU6cmVzb3VyY2Vfc2VydmVycyBkZWxldGU6cmVzb3VyY2Vfc2VydmVycyBjcmVhdGU6cmVzb3VyY2Vfc2VydmVycyByZWFkOmRldmljZV9jcmVkZW50aWFscyB1cGRhdGU6ZGV2aWNlX2NyZWRlbnRpYWxzIGRlbGV0ZTpkZXZpY2VfY3JlZGVudGlhbHMgY3JlYXRlOmRldmljZV9jcmVkZW50aWFscyByZWFkOnJ1bGVzIHVwZGF0ZTpydWxlcyBkZWxldGU6cnVsZXMgY3JlYXRlOnJ1bGVzIHJlYWQ6ZW1haWxfcHJvdmlkZXIgdXBkYXRlOmVtYWlsX3Byb3ZpZGVyIGRlbGV0ZTplbWFpbF9wcm92aWRlciBjcmVhdGU6ZW1haWxfcHJvdmlkZXIgYmxhY2tsaXN0OnRva2VucyByZWFkOnN0YXRzIHJlYWQ6dGVuYW50X3NldHRpbmdzIHVwZGF0ZTp0ZW5hbnRfc2V0dGluZ3MgcmVhZDpsb2dzIHJlYWQ6c2hpZWxkcyBjcmVhdGU6c2hpZWxkcyBkZWxldGU6c2hpZWxkcyB1cGRhdGU6dHJpZ2dlcnMgcmVhZDp0cmlnZ2VycyByZWFkOmdyYW50cyBkZWxldGU6Z3JhbnRzIHJlYWQ6Z3VhcmRpYW5fZmFjdG9ycyB1cGRhdGU6Z3VhcmRpYW5fZmFjdG9ycyByZWFkOmd1YXJkaWFuX2Vucm9sbG1lbnRzIGRlbGV0ZTpndWFyZGlhbl9lbnJvbGxtZW50cyBjcmVhdGU6Z3VhcmRpYW5fZW5yb2xsbWVudF90aWNrZXRzIHJlYWQ6dXNlcl9pZHBfdG9rZW5zIGNyZWF0ZTpwYXNzd29yZHNfY2hlY2tpbmdfam9iIGRlbGV0ZTpwYXNzd29yZHNfY2hlY2tpbmdfam9iIn0.iAQkHb78HI8ELqUX88KWPCi2vghdbu6fuLbsJWiyAlSbFQ_XVMCtnYPMm-lOtMuGbFe6EJ7qQz5s86QmNh5c6pYgXc4QxAC_8lYEABFOxTT4UHe4EcctMJ-I05h5E4EMs1TZ33Xaz4EsD6VfvqhaJk4P6siWp3CKBwlshewqsXIy5tyWirUUwEAwxfF6mZ5qLytkxtVCeuzZg53rzybFCK7AcfWV3C7slmdl6fPSIOpNA8JCl71MIpdWAB4cnlwYZ0veKUJ8LnZ_83pttLScccX1zNdFh0guFw6EFsCbARDZhEivvbcPLClpM8e7cU4h1UNS4x-IjEuw-5X8sP2kBg"
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", tokenString))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
// Read the response body
buf := new(bytes.Buffer)
io.Copy(buf, res.Body)
res.Body.Close()
w.Write(buf.Bytes())
}
func checkJwt(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
client := auth0.NewJWKClient(auth0.JWKClientOptions{URI: JWKS_URI})
log.Println(client.GetSecret(r))
audience := AUTH0_API_AUDIENCE
configuration := auth0.NewConfiguration(client, audience, AUTH0_API_ISSUER, jose.RS256)
//secret, _ := base64.URLEncoding.DecodeString("ZyxsZ0gKJKJmm8ID-YvBr_rg6ELNDhS4GGDDDsguzyvpNWHmd5BlCF5XtEQP6lCe")
//secret := []byte("ZyxsZ0gKJKJmm8ID-YvBr_rg6ELNDhS4GGDDDsguzyvpNWHmd5BlCF5XtEQP6lCe")
//secretProvider := auth0.NewKeyProvider(secret)
//audience := "WEzqFahxGbPk45vdxRVUxIkT9Pn756VT"
//configuration := auth0.NewConfiguration(secretProvider, []string{audience}, "https://shinofara.auth0.com", jose.RS256)
validator := auth0.NewValidator(configuration)
token, err := validator.ValidateRequest(r)
if err != nil {
fmt.Println(err)
response := Response{
Message: "Missing or invalid token.",
}
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(response)
} else {
// Ensure the token has the correct scope
result := checkScope(r, validator, token)
if result == true {
// If the token is valid and we have the right scope, we'll pass through the middleware
h.ServeHTTP(w, r)
} else {
response := Response{
Message: "You do not have the read:messages scope.",
}
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(response)
}
}
})
}
func checkScope(r *http.Request, validator *auth0.JWTValidator, token *jwt2.JSONWebToken) bool {
claims := map[string]interface{}{}
err := validator.Claims(r, token, &claims)
if err != nil {
fmt.Println(err)
return false
}
if strings.Contains(claims["scope"].(string), "read:messages") {
return true
} else {
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment