Created
July 30, 2017 12:48
-
-
Save shinofara/b540f50d6456951aa9ebccd71a6874a9 to your computer and use it in GitHub Desktop.
auth0-go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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