Added the option of validating JWT on user selected http handlers.
diff --git a/oauth.go b/oauth.go
new file mode 100644
index 0000000..c55beb7
--- /dev/null
+++ b/oauth.go
@@ -0,0 +1,144 @@
+package goscaffold
+
+import (
+ "context"
+ "encoding/json"
+ "github.com/SermoDigital/jose/crypto"
+ "github.com/SermoDigital/jose/jws"
+ "github.com/SermoDigital/jose/jwt"
+ "github.com/julienschmidt/httprouter"
+ "github.com/justinas/alice"
+ "net/http"
+)
+
+const params = "params"
+
+/* Errors to return */
+type Errors []string
+
+/*
+The SSO key parameters
+*/
+type ssoKey struct {
+ Alg string `json:"alg"`
+ Value string `json:"value"`
+ Kty string `json:"kty"`
+ Use string `json:"use"`
+ N string `json:"n"`
+ E string `json:"e"`
+}
+
+/*
+OAuth structure that provides http connection to the URL that has the public
+key for verifying the JWT token
+*/
+type OAuth struct {
+ keyURL string
+ client *http.Client
+}
+
+/*
+The interface functions offered to clients that act on OAuth param,
+used to verify JWT tokens for the Http handler functions client
+wishes to validate against (via SSOHandler).
+*/
+type OAuthService interface {
+ SSOHandler(p string, h func(http.ResponseWriter, *http.Request)) (string, httprouter.Handle)
+}
+
+/*
+SetParamsInRequest Sets the params and its values in the request
+*/
+func SetParamsInRequest(r *http.Request, ps httprouter.Params) *http.Request {
+ newContext := context.WithValue(r.Context(), params, ps)
+ return r.WithContext(newContext)
+}
+
+/*
+FetchParams fetches the param values, given the params in the request
+*/
+func FetchParams(r *http.Request) httprouter.Params {
+ ctx := r.Context()
+ return ctx.Value(params).(httprouter.Params)
+}
+
+/*
+SSOHandler offers the users the flexibility of choosing which http handlers
+need JWT validation.
+*/
+func (a *OAuth) SSOHandler(p string, h func(http.ResponseWriter, *http.Request)) (string, httprouter.Handle) {
+ return p, a.VerifyOAuth(alice.New().ThenFunc(h))
+}
+
+/*
+VerifyOAuth verifies the JWT token in the request using the public key configured
+via CreateOAuth constructor.
+*/
+func (a *OAuth) VerifyOAuth(next http.Handler) httprouter.Handle {
+
+ return func(rw http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+
+ jwt, err := jws.ParseJWTFromRequest(r)
+ if err != nil {
+ WriteErrorResponse(http.StatusBadRequest, err.Error(), rw)
+ return
+ }
+
+ /* Validate the JWT */
+ err = a.Validate(jwt)
+ if err != nil {
+ WriteErrorResponse(http.StatusBadRequest, err.Error(), rw)
+ return
+ }
+
+ /* Set the params in the request */
+ r = SetParamsInRequest(r, ps)
+ next.ServeHTTP(rw, r)
+ }
+
+}
+
+/*
+ValidateKey validate the jwt and return an error if it fails
+*/
+func (a *OAuth) Validate(jwt jwt.JWT) error {
+
+ r, err := a.client.Get(a.keyURL)
+
+ if err != nil {
+ return err
+ }
+
+ defer r.Body.Close()
+ ssoKey := &ssoKey{}
+ err = json.NewDecoder(r.Body).Decode(ssoKey)
+ if err != nil {
+ return err
+ }
+
+ /* Retrieve the Public Key */
+ publieKey, err := crypto.ParseRSAPublicKeyFromPEM([]byte(ssoKey.Value))
+ if err != nil {
+ return err
+ }
+
+ /* Return the status of validation */
+ return jwt.Validate(publieKey, crypto.SigningMethodRS256)
+}
+
+/*
+WriteErrorResponse write a non 200 error response
+*/
+func WriteErrorResponse(statusCode int, message string, w http.ResponseWriter) {
+ errors := Errors{message}
+ WriteErrorResponses(statusCode, errors, w)
+}
+
+/*
+WriteErrorResponses write our error responses
+*/
+func WriteErrorResponses(statusCode int, errors Errors, w http.ResponseWriter) {
+ w.WriteHeader(statusCode)
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(errors)
+}