Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

supabase graphql endpoint returns 401 {"message":"invalid signature"} on call with valid jwt in Authorization: Bearer header #504

Open
2 tasks done
DavidOrchard opened this issue Apr 1, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@DavidOrchard
Copy link

DavidOrchard commented Apr 1, 2024

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

The graphql endpoint for my project returns 401 {"message":"invalid signature"} when I use any user's session access_token as described in the docs. I can access the graphql endpoint from the https://supabase.com/dashboard/project//api/graphiql when impersonating that user.

To Reproduce

  1. Create user in db
  2. Setup Javascript client to call graphql
  3. Call api

JS code

  const apiKey = process.env.SUPABASE_ANON_KEY
  const Authorization = options.graphqlToken
  // call the graphql endpoint
  console.log('Authorization', Authorization)
  console.log('apiKey', apiKey)
  let response
  try {
    response = await fetch(options.graphqlPath, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization,
        apiKey
      },
      body: JSON.stringify({
        query: gqlQuery,
        variables,
      }),
    })
  } catch (err) {
    console.error(`Failed to fetch from ${options.graphqlPath}. Err: `, err)
    throw new BadGateway()
  }

  if (response.status != 200 && response.status != 201) {
    // Proxied endpoint call unsuccesful, exit
    const body = await response.text()
    console.error(
      `Failed to call query endpoint! graphqlPath: ${options.graphqlPath}
Status code: ${response.status}
Token length: ${options.graphqlToken.length}
Headers: ${JSON.stringify(response.headers)}
Response body: ${body}`,
    )
    throw new BadGateway()

output is

Authorization Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6Img4clRmbnZseG1xdjY1dXYiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzExOTg5Mzc4LCJpYXQiOjE3MTE5ODU3NzgsImlzcyI6Imh0dHBzOi8va2FiY2x5eGVzb2h1a293d3p3aWIuc3VwYWJhc2UuY28vYXV0aC92MSIsInN1YiI6IjE0MzgxMDkyLTBiMzgtNGUwMS1iNDYxLWM4MzNlYWVhMGI2YiIsImVtYWlsIjoiZXhhbXBsZUBlbWFpbC5jb20iLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTcxMTk4NTc3OH1dLCJzZXNzaW9uX2lkIjoiNGUxOWQ1NGYtODk2OC00ODEzLWFmOTAtYTYyMDdmMjA5YTZiIiwiaXNfYW5vbnltb3VzIjpmYWxzZX0.b5wOckaqQG020IRdLZ3QI6XOT7hHHy-I_Xjx3weor70
apiKey <hidden>
Failed to call query endpoint! graphqlPath: https://api.supabase.com/platform/projects/<project>/api/graphql
Status code: 401
Token length: 705
Headers: {}
Response body: {"message":"invalid signature"}
BadGateway [Error]

Expected behavior

I expect to have the endpoint returns the graphql.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: MacOS 14.4
  • Version of supabase-js: 2.39.3
  • Version of Node.js: 18.17.1

Additional context

Where is the "invalid signature" message generated? I looked through supabase, supabase-js, auth, auth-js, auth-helpers, pg_graphql, github.com/golang-jwt/jwt, https://pkg.go.dev/go.imperva.dev/demos/matrix-chat/internal/api/demo#ParseJWTClaims, and I could not find where that string is generated and where the 401 is returned.

The token shown above appears valid per the online jwt decoder at https://10015.io/tools/jwt-encoder-decoder as it's decoded as

{
  "aud": "authenticated",
  "exp": 1711989378,
  "iat": 1711985778,
  "iss": "https://<projectid>.supabase.co/auth/v1",
  "sub": "14381092-0b38-4e01-b461-c833eaea0b6b",
  "email": "[email protected]",
  "phone": "",
  "app_metadata": {
    "provider": "email",
    "providers": [
      "email"
    ]
  },
  "user_metadata": {},
  "role": "authenticated",
  "aal": "aal1",
  "amr": [
    {
      "method": "password",
      "timestamp": 1711985778
    }
  ],
  "session_id": "4e19d54f-8968-4813-af90-a6207f209a6b",
  "is_anonymous": false
}

JWT Header

{
  "alg": "HS256",
  "kid": "h8rTfnvlxmqv65uv",
  "typ": "JWT"
}

Separately, the docs are quite inconsistent about which headers and keys are required and the endpoints.
Relay example https://supabase.com/docs/guides/graphql/with-relay shows

fetch(`${SUPABASE_URL}/graphql/v1`
      apikey: SUPABASE_ANON_KEY,
      Authorization: `Bearer ${session?.access_token ?? SUPABASE_ANON_KEY}`,

Apollo example shows no apiKey header nor vallbck to anon key.

  const token = (await supabase.auth.getSession()).data.session?.access_token

  return {
    headers: {
      ...headers,
      Authorization: token ? `Bearer ${token}` : '',
    },

Quickstart docs at https://supabase.com/docs/guides/graphql also show /v1 in the url but my project's url clearly has no /v1 https://supabase.com/dashboard/project/<projectid>/api/graphiql. The quickstart docs link have a broken link to api, https://supabase.com/docs/guides/graphql#api-key-api_key

The graphiql explorer doesn't show the apiKey in the Headers section.

The graphql query that the explorer makes doesn't show the apiKey header.

@DavidOrchard DavidOrchard added the bug Something isn't working label Apr 1, 2024
@TheOtherBrian1 TheOtherBrian1 transferred this issue from supabase/supabase Apr 1, 2024
@DavidOrchard
Copy link
Author

I was using the url, https://api.supabase.com/platform/projects//api/graphql from the graphiql explorer instead of https://.supabase.co/graphql/v1. I'm curious why this URL won't work when I see it in the browser.

The return from the /api/graphl etc endpoints should be a lot clearer than "invalid signature".

I am still curious how that error is generated.

The doc comments remain valid.

@kangmingtay kangmingtay transferred this issue from supabase/auth Apr 2, 2024
@kangmingtay
Copy link
Member

@DavidOrchard did you happen to modify the JWT payload before sending the request?

the JWT verification is handled by postgREST so i doubt it's an issue with pg_graphql

@DavidOrchard
Copy link
Author

I did not modify the payload

@imor
Copy link
Contributor

imor commented Apr 3, 2024

@steve-chavez any idea what could cause the 401 error?

@steve-chavez
Copy link
Member

steve-chavez commented Apr 3, 2024

@imor This should be coming from Kong:

https://stackoverflow.com/questions/45164319/kong-jwt-invalid-signature

PostgREST errors come in a different (more informative) format: https://postgrest.org/en/v12/references/errors.html#errors-from-postgrest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants