auth0-samples / auth0-golang-api-samples

Auth0 Integration Samples for Go REST API Services
https://auth0.com/docs/quickstart/backend/golang
MIT License
128 stars 67 forks source link

Error in sample app due to dependency issue? #5

Closed Kamil1 closed 7 years ago

Kamil1 commented 7 years ago

Below is the text of the original documentation of the issue I was having with running this sample app:

I am creating a new application, and have decided to use Golang and Auth0 as opposed to my usual Node.js + Firebase workflow. I am building an API, and cannot get authenticated endpoints to work. I have downloaded the Auth0 created Go sample app (https://github.com/auth0-samples/auth0-golang-web-api), and it does not seem to work. As-is, it does not compile. Error is displayed below:

πŸ‘‰  go run main.go
# command-line-arguments
./main.go:33: undefined: errors in errors.New

I updated that line of code to: log.Fatal("AUTH0_CLIENT_SECRET not set")

After setting ENV variables using bash export:

export AUTH0_CLIENT_ID=***
export AUTH0_CLIENT_SECRET=***
export AUTH0_DOMAIN=***

and running the main.go file, I get the following response when I ping the /secured/ping endpoint: key is of invalid type

The header of the API request has an Authorization field set to: bearer <ID_TOKEN> This is the same result I receive when I attempt to reach an endpoint in my code. Are the quick start guides outdated? Am I setting something up incorrectly? I cannot get Authorization to work.

--

I have since narrowed it down to being an issue with the jwt-go dependency. I am almost certain that this is a bug and not due to user error.

Kamil1 commented 7 years ago

This issue has not been resolved. Compilation is successful, however unexpected response of "key is in invalid type" is still occurring when calling /secured/ping

chenkie commented 7 years ago

What is the bug with jwt-go you mention?

Kamil1 commented 7 years ago

When navigating to the project

πŸ‘‰  pwd
/Users/kamilkhan/Development/bread-server/src/github.com/auth0-golang-web-api/00-Starter-Seed

which has all of the proper files created, with the .env file containing all of the proper information provided in my Auth0 dashboard

πŸ‘‰  ls -al
total 32
drwxr-xr-x  6 kamilkhan  staff   204 23 Jan 09:35 .
drwxr-xr-x  7 kamilkhan  staff   238 22 Jan 20:34 ..
-rw-r--r--  1 kamilkhan  staff   213 23 Jan 09:36 .env
-rw-r--r--  1 kamilkhan  staff    14 22 Jan 20:34 .gitignore
-rw-r--r--  1 kamilkhan  staff   682 22 Jan 20:34 README.md
-rw-r--r--@ 1 kamilkhan  staff  1630 22 Jan 20:30 main.go

I run go get to ensure all dependencies are present

πŸ‘‰  go get .

I then go run the app

πŸ‘‰  go run main.go

I cURL a GET request to the unsecured endpoint in the project to ensure that everything is running correctly

πŸ‘‰  curl --request GET \
> --url http://localhost:3001/ping
{"text":"All good. You don't need to be authenticated to call this"}%

Seems to be working. I then get a id_token to test the secured endpoint. I create a cURL request to Auth0 to retrieve my token. I have omitted the password in this code snippet, however the call was made with a correct password (hence the id_token being returned)

πŸ‘‰  curl --request POST \
  --url 'https://bread.auth0.com/oauth/ro' \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --data '{ "client_id": "spbFQbxx6e1APknYApdZZ5Kghu3r8lon", "connection": "Username-Password-Authentication", "grant_type": "password", "username": "kamil.z.khan@gmail.com", "password": "<**********>", "scope":"openid"}'
{"id_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JyZWFkLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1ODgzZTJlOWJkZjg0NTMzNjk3Y2QyZDUiLCJhdWQiOiJzcGJGUWJ4eDZlMUFQa25ZQXBkWlo1S2dodTNyOGxvbiIsImV4cCI6MTQ4NTIyOTA0MCwiaWF0IjoxNDg1MTkzMDQwfQ.kUMRYNsYwTToFF0TYGmiepUtvj7JikZAi7HVBfMdi5Y","access_token":"Psim47cBvIMV2aAL","token_type":"bearer"}%

I then pass this token into the Authorization header when making a GET request to the secured endpoint of the Go server.

πŸ‘‰  curl --request GET \
  --url http://localhost:3001/secured/ping \
  --header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JyZWFkLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1ODgzZTJlOWJkZjg0NTMzNjk3Y2QyZDUiLCJhdWQiOiJzcGJGUWJ4eDZlMUFQa25ZQXBkWlo1S2dodTNyOGxvbiIsImV4cCI6MTQ4NTIyOTA0MCwiaWF0IjoxNDg1MTkzMDQwfQ.kUMRYNsYwTToFF0TYGmiepUtvj7JikZAi7HVBfMdi5Y'
key is of invalid type

I get an error stating that the key is of invalid type.

Googling this error brings up the following Git Issue threads from the jwt-go library this application uses:

https://github.com/dgrijalva/jwt-go/issues/65 https://github.com/dgrijalva/jwt-go/issues/147 https://github.com/dgrijalva/jwt-go/issues/76

I am not familiar enough with Go nor JWTs to properly attempt to fix the issue myself. All issues above were closed, which seems to suggest that the jwt-go library is functional, but not being called correctly.

chenkie commented 7 years ago

It sounds like it could be an issues the signing algorithm. Your sample ID token is signed with HS256. Is your middleware configured to use that as the alg?

Kamil1 commented 7 years ago

These issues are present with the current repo as-is. That is, the following is the middleware being used:

jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
          ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
            secret := os.Getenv("AUTH0_CLIENT_SECRET")          
            if secret == "" {
              log.Fatal("AUTH0_CLIENT_SECRET is not set")
            }
            return secret, nil
          },
        })

Modifying the middleware to the following does not fix the issue:

jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
          ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
            secret := os.Getenv("AUTH0_CLIENT_SECRET")          
            if secret == "" {
              log.Fatal("AUTH0_CLIENT_SECRET is not set")
            }
            return secret, nil
          },
          SigningMethod: jwt.SigningMethodHS256, // THIS LINE WAS ADDED
        })
kukicado commented 7 years ago

Hi @Kamil1. I dug into this a little bit and found the issue.

The secret needs to be a byte slice, not a string. See the code below on how to convert the string to byte slice. I will submit a PR to update our sample. Thanks! Let me know if this works for you.

jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
        ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
            secret := []byte(os.Getenv("AUTH0_CLIENT_SECRET"))

            if len(secret) == 0 {
                log.Fatal("AUTH0_CLIENT_SECRET is not set")
            }

            return secret, nil
        },
    })
Kamil1 commented 7 years ago

It works well! Good catch. For completeness, documentation on the Auth0 website should be updated as well, not just this repo. The current code here contains the bug outlined above.

chenkie commented 7 years ago

Thanks @kukicado.

@Kamil1 I will update the docs πŸ‘