Add Auth0 JWT support
This commit is contained in:
parent
a897158bcc
commit
83f90c1bbd
@ -2,3 +2,4 @@ example
|
||||
tmp
|
||||
*.md
|
||||
web/build
|
||||
docker-compose.*
|
||||
|
40
README.md
40
README.md
@ -234,7 +234,7 @@ auth:
|
||||
# type: jwt
|
||||
# cookie: _app_session
|
||||
# secret: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: /secrets/public_key.pem
|
||||
# public_key_type: ecdsa #rsa
|
||||
|
||||
database:
|
||||
@ -283,10 +283,44 @@ SG_AUTH_URL
|
||||
SG_AUTH_PASSWORD
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
You can only have one type of authentication enabled. You can either pick Rails or JWT. Uncomment the one you use and leave the rest commented out.
|
||||
|
||||
#### JWT Tokens
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
type: jwt
|
||||
provider: auth0 #none
|
||||
cookie: _app_session
|
||||
secret: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
public_key_file: /secrets/public_key.pem
|
||||
public_key_type: ecdsa #rsa
|
||||
```
|
||||
|
||||
For JWT tokens we currently support tokens from a provider like Auth0
|
||||
or if you have a custom solution then we look for the `user_id` in the
|
||||
`subject` claim of of the `id token`. If you pick Auth0 then we derive two variables from the token `user_id` and `user_id_provider` for to use in your filters.
|
||||
|
||||
We can get the JWT token either from the `authorization` header where we expect it to be a `bearer` token or if `cookie` is specified then we look there.
|
||||
|
||||
For verified either a `secret` or a public key (ecdsa or rsa) is required. When using public keys they have to be in a PEM format file.
|
||||
|
||||
## Deployment
|
||||
|
||||
How do I deploy the Super Graph service with my existing rails app? You have several options here. Esentially you need to ensure your app's session cookie
|
||||
will be passed to this service.
|
||||
How do I deploy the Super Graph service with my existing rails app? You have several options here. Esentially you need to ensure your app's session cookie will be passed to this service.
|
||||
|
||||
#### Custom Docker Image
|
||||
|
||||
Create a `Dockerfile` like the one below to roll your own
|
||||
custom Super Graph docker image. And to build it `docker build -t my-super-graph .`
|
||||
|
||||
```dockerfile
|
||||
FROM dosco/super-graph:latest
|
||||
WORKDIR /app
|
||||
COPY *.yml ./
|
||||
```
|
||||
|
||||
#### Deploy under a subdomain
|
||||
For this to work you have to ensure that the option `:domain => :all` is added to your rails app config `Application.config.session_store` this will cause your rails app to create session cookies that can be shared with sub-domains. More info here <http://excid3.com/blog/sharing-a-devise-user-session-across-subdomains-with-rails-3/>
|
||||
|
3
dev.yml
3
dev.yml
@ -50,9 +50,10 @@ auth:
|
||||
|
||||
# auth:
|
||||
# type: jwt
|
||||
# provider: auth0
|
||||
# cookie: _app_session
|
||||
# secret: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: /secrets/public_key.pem
|
||||
# public_key_type: ecdsa #rsa
|
||||
|
||||
database:
|
||||
|
2
go.mod
2
go.mod
@ -1,7 +1,7 @@
|
||||
module github.com/dosco/super-graph
|
||||
|
||||
require (
|
||||
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3
|
||||
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/garyburd/redigo v1.6.0
|
||||
|
3
prod.yml
3
prod.yml
@ -43,9 +43,10 @@ auth:
|
||||
|
||||
# auth:
|
||||
# type: jwt
|
||||
# provider: auth0
|
||||
# cookie: _app_session
|
||||
# secret: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: /secrets/public_key.pem
|
||||
# public_key_type: ecdsa #rsa
|
||||
|
||||
database:
|
||||
|
@ -15,8 +15,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
userIDKey = struct{}{}
|
||||
errSessionData = errors.New("error decoding session data")
|
||||
userIDProviderKey = struct{}{}
|
||||
userIDKey = struct{}{}
|
||||
errSessionData = errors.New("error decoding session data")
|
||||
)
|
||||
|
||||
func headerHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
|
@ -4,15 +4,27 @@ import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
const (
|
||||
jwtBase int = iota
|
||||
jwtAuth0
|
||||
)
|
||||
|
||||
func jwtHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
var key interface{}
|
||||
var jwtProvider int
|
||||
|
||||
cookie := conf.GetString("auth.cookie")
|
||||
|
||||
provider := conf.GetString("auth.provider")
|
||||
if provider == "auth0" {
|
||||
jwtProvider = jwtAuth0
|
||||
}
|
||||
|
||||
conf.BindEnv("auth.secret", "SG_AUTH_SECRET")
|
||||
secret := conf.GetString("auth.secret")
|
||||
|
||||
@ -75,7 +87,17 @@ func jwtHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*jwt.StandardClaims); ok {
|
||||
ctx := context.WithValue(r.Context(), userIDKey, claims.Id)
|
||||
ctx := r.Context()
|
||||
|
||||
if jwtProvider == jwtAuth0 {
|
||||
sub := strings.Split(claims.Subject, "|")
|
||||
if len(sub) != 2 {
|
||||
ctx = context.WithValue(ctx, userIDProviderKey, sub[0])
|
||||
ctx = context.WithValue(ctx, userIDKey, sub[1])
|
||||
}
|
||||
} else {
|
||||
ctx = context.WithValue(ctx, userIDKey, claims.Subject)
|
||||
}
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
|
15
serv/http.go
15
serv/http.go
@ -153,15 +153,24 @@ func authCheck(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
func varValues(ctx context.Context) map[string]interface{} {
|
||||
userIDFn := fasttemplate.TagFunc(func(w io.Writer, _ string) (int, error) {
|
||||
uidFn := fasttemplate.TagFunc(func(w io.Writer, _ string) (int, error) {
|
||||
if v := ctx.Value(userIDKey); v != nil {
|
||||
return w.Write([]byte(v.(string)))
|
||||
}
|
||||
return 0, errNoUserID
|
||||
})
|
||||
|
||||
uidpFn := fasttemplate.TagFunc(func(w io.Writer, _ string) (int, error) {
|
||||
if v := ctx.Value(userIDProviderKey); v != nil {
|
||||
return w.Write([]byte(v.(string)))
|
||||
}
|
||||
return 0, errNoUserID
|
||||
})
|
||||
|
||||
return map[string]interface{}{
|
||||
"USER_ID": userIDFn,
|
||||
"user_id": userIDFn,
|
||||
"USER_ID": uidFn,
|
||||
"user_id": uidFn,
|
||||
"USER_ID_PROVIDER": uidpFn,
|
||||
"user_id_provider": uidpFn,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user