shaj13 / go-guardian

Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to create powerful modern API and web authentication.
MIT License
543 stars 55 forks source link

How to setup jwt strategy properly #100

Closed shachardevops closed 3 years ago

shachardevops commented 3 years ago

Main

func main() {
    setupGoGuardian()
    http.Handle("/ping", controllers.Ping())
    http.Handle("/login", middlewares.Auth(http.HandlerFunc(controllers.CreateToken())))
    fmt.Println("starting to listen on port " + config.Port)
    http.ListenAndServe(":"+config.Port, nil)
}

SetupGoGuardian

func setupGoGuardian() {
    rs := middlewares.RotatedSecrets{
        Secrets: make(map[string][]byte),
    }
    cache := libcache.LRU.New(0)
    cache.SetTTL(time.Minute * 5)
    cache.RegisterOnExpired(func(key, _ interface{}) {
        cache.Peek(key)
    })
    basicStrategy := basic.NewCached(users.ValidateUser, cache)
    jwtStrategy := jwt.New(cache, rs)
    middlewares.Strategy = union.New(jwtStrategy, basicStrategy)
}

Auth Middleware

func Auth(next http.Handler) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // log.Println("Executing Auth Middleware")
        _, user, errList := Strategy.AuthenticateRequest(r)

        if errList != nil {
            code := http.StatusUnauthorized
            for _, err := range errList.(union.MultiError) {
                switch err.(type) {
                case *InternalError:
                    code = http.StatusInternalServerError
                }
            }
            http.Error(w, http.StatusText(code), code)
            return
        }
        log.Printf("User %s Authenticated\n", user.GetUserName())
        r = auth.RequestWithUser(user, r)
        next.ServeHTTP(w, r)
    })
}

Controller CreateToken

func CreateToken() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodPost:
            u := auth.User(r)
//What should I do here? how can I add the jwt to the RotatedSecrets 
// And how can I add extra fields to the token for example permissions, so the token will include permissions: "kill","example"
            token, err := jwt.IssueAccessToken(u, ??)
                        if err != nil { 
                                //something
                        }
            body := fmt.Sprintf("token: %s \n", token)
            w.Write([]byte(body))
        default:
            http.Error(w, "method is not allowed", http.StatusMethodNotAllowed)
            return
        }
    }
}

And what should I do with the rotatedSecret struct


type RotatedSecrets struct {
    Secrets          map[string][]byte
    LatestID         string
    RotationDuration time.Duration
    LastRotation     time.Time

}

func (r RotatedSecrets) KID() string {
    if time.Now().After(r.LastRotation) {
        r.LastRotation = time.Now().Add(r.RotationDuration)
        r.LatestID = "your generated id"
        r.Secrets[r.LatestID] = []byte("your generated secrets") <<<<<where should I get the generated secrets?
    }
    return r.LatestID
}

func (r RotatedSecrets) Get(kid string) (key interface{}, alg string, err error) {
    s, ok := r.Secrets[kid]
    if ok {
        return s, jwt.HS256, nil
    }
    return nil, "", fmt.Errorf("Invalid KID %s", kid)
}
shachardevops commented 3 years ago

@shaj13 can you please help?

shaj13 commented 3 years ago

@shachardevops what is your question? library exposing API not an end-to-end solution, you should construct your app as you need.