Echo: JWT middleware: support RS256 algorithm

Created on 21 Aug 2016  路  3Comments  路  Source: labstack/echo

Description

JWT middleware support RS256 algorithm 馃檹

Checklist

  • [x] Dependencies installed
  • [x] No typos

    Expected behaviour

JWTConfig struct {
        // Skipper defines a function to skip middleware.
        Skipper Skipper

        // Signing key to validate token.
        // Required.
-       SigningKey []byte `json:"signing_key"`
+       SigningKey interface{} `json:"signing_key"`

        // Signing method, used to check token signing method.
        // Optional. Default value HS256.
        SigningMethod string `json:"signing_method"`

        // Context key to store user information from the token into context.
        // Optional. Default value "user".
        ContextKey string `json:"context_key"`

        // Claims are extendable claims data defining token content.
        // Optional. Default value jwt.MapClaims
        Claims jwt.Claims

        // TokenLookup is a string in the form of "<source>:<name>" that is used
        // to extract token from the request.
        // Optional. Default value "header:Authorization".
        // Possible values:
        // - "header:<name>"
        // - "query:<name>"
        TokenLookup string `json:"token_lookup"`
    }

Test Code

func TestJWT_RS256(t *testing.T) {
    publicKeyStr := `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvirSgZYgExeWREezmBvZ
9PUxrmwDS5DACGhmXNgKpjQRenGC5vuDDXCC97rMHRvFCZZnyXAVxawYpN9wNVaF
sR4YmJHjRHeZrFpZHEqb6YteL3biNgyV6Uz6naflubXOa7goX6CNZ0a+MK6zD66L
3T9VcOSzLuxr/o+eaW84C58uDdLDY0RJXtD0nK5N0/I3l9C0GgrY6rlYs0POtJP1
FlxBnr7XhHi/xyUdXYrVpe720hz10u5LDw4Se4hA/P+0q5n7GJ43VBAMPq+tU74a
5HPtm8Cf2EgkAfgOGUbVs7hcy+mX0a9ZjDbDiFjBqELsZtNKJgWeeVsD8FOhvqbg
pDCXanEFiPkzm0+R2rrbrTHQC2fG3kv9y+H3gVdimaIQLVFBHj6HUyQeR73ahbuV
fWLpDx/pJ99EFymwxO2cBvlT9LqTOOCuePJxbsXJGTq30jGZswghbFx/NY1GIVSR
9BNvyOVjy0+AbriJMiVk0WDfHXDxd8kCxUJoMdwYa39JIuoIlVggesXdPijBXGT4
HRyC/oW2IrfbJwcYO12SbmbIix6aGVMcVlKvP0TW3tSmn1K7GRsI+y8WnLzPeboc
tsbMTp8ya8wmggGtbsBZQT2FhGiI0f4XGre3Y6NDoc0IZFuq7RCLnMVsoY66zICu
3pOseSoebApaotc7lhchtlECAwEAAQ==
-----END PUBLIC KEY-----`

    e := echo.New()
    req := test.NewRequest(echo.GET, "/", nil)
    res := test.NewResponseRecorder()
    token := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZXhwIjoxNDcxODQ1NjMxLCJuYW1lIjoiSm9uIFNub3cifQ.d5-OZYdilvFtYS0dUanxgdSHUsln8VCAG3JHzC44G4UuXmD0LF0Dw1um7vV0kRk6VERD8_OcNJxRzCTN2CQ-FYymQO1YRjtX36C8rx96QQd-C07jEgglSiNZtjLYwXqBRsHHJPKSh-qtDBm9uzwxDzYbnv3QEVrT2vTyJ7Zfm4RQGVKJ1K1t3kdYvnJToyvOi-P8hQp1U-LK8sCX5MsQ0AeE53xNq7DJMJSikCBGJyE-K08upVL7kwyRgkZ5uNLhMCGLDxO-jQRHZFXrqKXP9m06myzQPPtpWw7dVf2H4YBgJztd9cgxz85vXOPLhwM8kM10C6x3UqIcpcZlhMQTMjKIHXrZ80zM9YLT7iZ034EK51bDZCTh0CaZ-ggWEbeKB45T0ICkxwLLaOqfZgdK5ix5qZ-7Z69GQBduoSbDYcv047dQyxiY0wlbRTi1ahKcJ1ejlVaMWRWWa5DHptJJVRbpsTVZv8fgZ5483Q-YJfu4XvM21GAGqJbZO8BXPDG893jUPbMmX2V0Yzp1_YRE_kCjO7VFElcSJguuvVAnDs7tqpSxQhnGN3ARpbvG2okBWfDTgxWv76LqY7yHfMdmNJ3J4q69S3xZdW04ppiYYYAE-Djc3yH1H18Hv52VnxmJcPkdtyfhbE8T7sQIXAqunPVJu9oYQLS_LTLTK5Y3jyg"
    auth := bearer + " " + token
    req.Header().Set(echo.HeaderAuthorization, auth)

    ctx := e.NewContext(req, res)
    handler := func(c echo.Context) error {
        return c.String(http.StatusOK, "test")
    }

    publicKey, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(publicKeyStr))

    // Valid JWT
    config := JWTConfig{
        Skipper: func(c echo.Context) bool {
            return false
        },
        ContextKey:    "user",
        SigningKey:    publicKey,
        SigningMethod: "RS256",
        TokenLookup:   "header:" + echo.HeaderAuthorization,
    }
    jwtMiddlewareFunc := JWTWithConfig(config)(handler)
    if assert.NoError(t, jwtMiddlewareFunc(ctx)) {
        user := ctx.Get("user").(*jwt.Token)
        claims := user.Claims.(jwt.MapClaims)
        assert.Equal(t, claims["name"], "Jon Snow")
        assert.Equal(t, claims["admin"], true)
    }
}
bug

Most helpful comment

Hi, this is an interesting feature to be added. This can be added to jwt.go (line 126) where the parser is called. The third parameter can return the signing key according to the signing algorithm.

Like this:

// getSigningKey returns a interface that represents the signing key based on SigningMethod
func getSigningKey(config JWTConfig) (interface{}, error) {
    if config.SigningMethod == AlgorithmRS256 {
        signkey, err := jwt.ParseRSAPublicKeyFromPEM(config.SigningKey)
        if err != nil {
            return nil, err
        }
        return signkey, nil
    }
    return config.SigningKey, nil
}

Can I make a pull request?
What do you think?

All 3 comments

Thanks!

Hi, this is an interesting feature to be added. This can be added to jwt.go (line 126) where the parser is called. The third parameter can return the signing key according to the signing algorithm.

Like this:

// getSigningKey returns a interface that represents the signing key based on SigningMethod
func getSigningKey(config JWTConfig) (interface{}, error) {
    if config.SigningMethod == AlgorithmRS256 {
        signkey, err := jwt.ParseRSAPublicKeyFromPEM(config.SigningKey)
        if err != nil {
            return nil, err
        }
        return signkey, nil
    }
    return config.SigningKey, nil
}

Can I make a pull request?
What do you think?

This has been referenced by other issues as the correct way to use RS256 in echo, is this actually legit, because it seems like a terrible way to use RS256. and is 100% needed in echo.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

younisshah picture younisshah  路  4Comments

toorop picture toorop  路  4Comments

arun0009 picture arun0009  路  3Comments

wangxianzhuo picture wangxianzhuo  路  4Comments

linux-support picture linux-support  路  3Comments