5
  1. Im using next.js auth0 and a custom golang api backend and I'm having trouble getting the decoded token on the backend side.
  2. On the frontend side I followed this tutorial - https://auth0.com/docs/quickstart/webapp/nextjs/01-login
  3. and I managed to send the accessToken to my backend API successfully
  4. on the backend side I followed this tutorial - https://auth0.com/docs/quickstart/backend/golang/01-authorization
  5. The middleware has successfully verified the token

Example middleware from auth0 implementation

func EnsureValidToken(next http.Handler) http.Handler {
    // EnsureValidToken is a middleware that will check the validity of our JWT.
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }
    issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/")
    if err != nil {
        log.Fatalf("Failed to parse the issuer url: %v", err)
    }

    provider := jwks.NewCachingProvider(issuerURL, 5*time.Minute)

    jwtValidator, err := validator.New(
        provider.KeyFunc,
        validator.RS256,
        issuerURL.String(),
        []string{os.Getenv("AUTH0_AUDIENCE")},
        validator.WithCustomClaims(
            func() validator.CustomClaims {
                return &CustomClaims{}
            },
        ),
        validator.WithAllowedClockSkew(time.Minute),
    )
    if err != nil {
        log.Fatalf("Failed to set up the jwt validator")
    }

    errorHandler := func(w http.ResponseWriter, r *http.Request, err error) {
        log.Printf("Encountered error while validating JWT: %v", err)

        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusUnauthorized)
        w.Write([]byte(`{"message":"Failed to validate JWT."}`))
    }

    middleware := jwtmiddleware.New(
        jwtValidator.ValidateToken,
        jwtmiddleware.WithErrorHandler(errorHandler),
    )

    return middleware.CheckJWT(next)
}

Example token enter image description here

I'm using https://docs.gofiber.io/ to handle the HTTP methods

Main function

func main() {
    // This is to translate the net/http -> fiber http
    var ensureValidToken = adaptor.HTTPMiddleware(EnsureValidToken)

    app := fiber.New()
    app.Use(cors.New())
    app.Use(logger.New())
    // routes
    app.Use(ensureValidToken)
    app.Get("/api/books", getAll)

    app.Listen(":8080")
}

func getAll(c *fiber.Ctx) error {
       token := c.Context().Value(jwtmiddleware.ContextKey{}).(*validator.ValidatedClaims)

        // The above code will always panic, I'm assuming that it already stored in the context since it passes the validation
}

Panic example

panic: interface conversion: interface {} is nil, not *validator.ValidatedClaims

I dig deeper into the auth0 golang implementation, it does store in the context, I think the translation between http.Request to fiber HTTP failed

r = r.Clone(context.WithValue(r.Context(), ContextKey{}, validToken))
airsoftFreak
  • 1,450
  • 5
  • 34
  • 64

2 Answers2

0

Seems like more people have faced the same issue when they used the gofiber adaptor. The way others have solved it was to create their own implementation of HTTPMiddleware middleware adaptor with the only change being that they set the context to the fiber.Ctx.

You can find an the thread on the gofiber/adaptor github page here: https://github.com/gofiber/adaptor/issues/27#issuecomment-1120428400

knetsi
  • 1,601
  • 1
  • 16
  • 18
0

I got the same panic in the gin framework, I resolved the panic error by changing the code snippet to c.Request.Context().Value() but this is not available in fiber framework. If you want the decoded jwt token either you can get it from the header of the fiber context and decode it appropriately inside the controller, and pass the token you get from the header to the below function and decode.

import (
        extract "github.com/golang-jwt/jwt"
        "fmt"
        )
func Extractor(tokenString string) {
    token, _, err := new(extract.Parser).ParseUnverified(tokenString, extract.MapClaims{})
    if err != nil {
        fmt.Printf("Error %s", err)
    }
    if claims, ok := token.Claims.(extract.MapClaims); ok {
        // obtains claims
        subId := fmt.Sprint(claims["sub"])
        fmt.Println(subId)
    }
}

Implement your logic after this and pass the values you needed to the next handler.

Ouroborus
  • 16,237
  • 4
  • 39
  • 62