question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`JWSError JWSInvalidSignature`-Error on firebase

See original GitHub issue

I have a project using docker-compose:

version: '3.7'
services:
  db:
    image: 'mdillon/postgis'
    # specify container name to make it easier to run commands.
    # for example, you could run docker exec -i postgres psql -U postgres postgres < schema.sql to run an SQL file against the Postgres database
    container_name: v_db
    restart: always
    env_file:
      - ./.env
    ports:
      # make the Postgres database accessible from outside the Docker container on port 5432
      - '5432:5432'
    volumes:
      - db_data:/var/lib/postgresql/data
      - sik_data:/shared
    # hasura needs higher max_locks_per_transaction
    command: postgres -c max_locks_per_transaction=2000
  auth:
    build:
      context: ./auth
    container_name: v_auth
    restart: always
    env_file:
      - ./.env
    expose:
      - '7000'
    ports:
      - '7000:7000'
    depends_on:
      - db
      - graphql
  graphql:
    image: 'hasura/graphql-engine:v1.1.0'
    container_name: v_graphql
    ports:
      - '8080:8080'
    depends_on:
      - db
    restart: always
    env_file:
      - ./.env
    command:
      - graphql-engine
      - serve
  caddy:
    image: 'caddy/caddy:alpine'
    container_name: v_caddy
    depends_on:
      - db
      - graphql
    restart: always
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
      - caddy_certs:/data/caddy
      - caddy_config:/root/.config/caddy
volumes:
  db_data:
  caddy_certs:
  sik_data:
  caddy_config:

This is the server.js file in the auth server:

'use strict'
// see: https://nodejs.org/de/docs/guides/nodejs-docker-webapp/

const Hapi = require('@hapi/hapi')
// see: https://firebase.google.com/docs/auth/admin/manage-users
const admin = require('firebase-admin')
const postgres = require('postgres')

const serviceAccount = require('./config.js')

const server = new Hapi.Server({
  host: '0.0.0.0',
  port: 7000,
})

const sql = postgres(process.env.HASURA_GRAPHQL_DATABASE_URL)

let firebaseInitializationError = null
// Initialize the Firebase admin SDK with your service account credentials
if (serviceAccount) {
  try {
    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
    })
  } catch (e) {
    firebaseInitializationError = e
  }
}

async function start() {
  server.route({
    method: 'GET',
    path: '/{uid}',
    handler: async (req, h) => {
      //console.log('serviceAccount:', serviceAccount)
      // Throw 500 if firebase is not configured
      if (!serviceAccount) {
        return h.response('Firebase not configured').code(500)
      }
      // Check for errors initializing firebase SDK
      if (firebaseInitializationError) {
        console.log('firebaseInitializationError:', firebaseInitializationError)
        return h
          .response(
            `firebase initalization error: ${firebaseInitializationError.message}`,
          )
          .code(500)
      }

      const { uid } = req.params
      //console.log('uid:', uid)
      if (!uid) {
        return h.response('no uid was passed').code(500)
      }

      //console.log('will query now')
      // fetch id and user_role
      return sql`select * from person where account_id = ${uid}`
        .then(persons => {
          //console.log('persons from query result:', persons)
          if (!persons) {
            return h.response('Got no persons when querying db').code(500)
          }
          const person = persons[0]
          if (!person) {
            return h.response('Got no person when querying db').code(500)
          }
          const { id, user_role } = person
          if (!id) {
            return h.response('Got no person_id when querying db').code(500)
          }
          if (!user_role) {
            return h
              .response('Got no person-user_role when querying db')
              .code(500)
          }
          const hasuraVariables = {
            'https://hasura.io/jwt/claims': {
              'x-hasura-default-role': user_role,
              'x-hasura-allowed-roles': [user_role],
              'x-hasura-user-id': id,
            },
          }

          return admin
            .auth()
            .createCustomToken(uid, hasuraVariables)
            .then(customToken => {
              //console.log('customToken:', customToken)
              // Send token back to client
              return h.response(customToken)
            })
            .catch(adminError => {
              console.log('Error creating custom token:', adminError)
              h.response(
                `Error creating custom token: ${adminError.message}`,
              ).code(500)
            })
        })
        .catch(sqlError => {
          console.log('Error querying db:', sqlError)
          h.response(`Error querying db: ${sqlError.message}`).code(500)
        })
    },
  })
  await server.start()
  console.log('JSON-API-Server running at:', server.info.uri)
}

process.on('unhandledRejection', err => {
  console.log(err)
  process.exit(1)
})

start()

The auth server returns a token generated by above code. The token is declared valid on jwt.io but only if declared as HS256, not when declared as RS256. Which baffles me.

This returned token is used client side to sing in:

let res
try {
  res = await axios.get(`https://auth.vermehrung.ch/${user.uid}`)
} catch (error) {
  return console.log(error)
}
const token = res.data
firebase
  .auth()
  .signInWithCustomToken(token)
  .catch(error => {
    console.log('Error signing in with custom token:', error)
  })

This works fine.

What does not work is the calls to hasura.

If I set the type in the .env file of docker to HS256:

HASURA_GRAPHQL_JWT_SECRET={"type":"HS256", "jwk_url": "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com", "audience": "vermehrung-f48c4", "issuer": "https://securetoken.google.com/vermehrung-f48c4"}

The error is:

{
  "type": "http-log",
  "timestamp": "2020-03-10T13:06:52.020+0000",
  "level": "error",
  "detail": {
    "operation": {
      "error": {
        "path": "$",
        "error": "Malformed Authorization header",
        "code": "invalid-headers"
      },
      "request_id": "90e5647f-579c-4bac-9d88-3bf83c89ba80",
      "response_size": 78,
      "raw_query": "{\"operationName\":\"TreeQueryForRoot\",\"variables\":{\"artFilter\":{\"id\":{\"_is_null\":false}},\"eventFilter\":{\"id\":{\"_is_null\":false}},\"gartenFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"kulturFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"herkunftFilter\":{\"id\":{\"_is_null\":false}},\"personFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"sammlungFilter\":{\"id\":{\"_is_null\":false}},\"lieferungFilter\":{\"id\":{\"_is_null\":false}},\"sammelLieferungFilter\":{\"id\":{\"_is_null\":false}},\"teilkulturFilter\":{\"id\":{\"_is_null\":false}},\"zaehlungFilter\":{\"id\":{\"_is_null\":false}}},\"query\":\"query TreeQueryForRoot($artFilter: art_bool_exp!, $eventFilter: event_bool_exp!, $gartenFilter: garten_bool_exp!, $kulturFilter: kultur_bool_exp!, $herkunftFilter: herkunft_bool_exp!, $personFilter: person_bool_exp!, $sammlungFilter: sammlung_bool_exp!, $teilkulturFilter: teilkultur_bool_exp!, $zaehlungFilter: zaehlung_bool_exp!, $lieferungFilter: lieferung_bool_exp!, $sammelLieferungFilter: sammel_lieferung_bool_exp!) {\\n  garten(where: $gartenFilter) {\\n    id\\n    __typename\\n  }\\n  art(where: $artFilter) {\\n    id\\n    __typename\\n  }\\n  event(where: $eventFilter) {\\n    id\\n    __typename\\n  }\\n  zaehlung(where: $zaehlungFilter) {\\n    id\\n    __typename\\n  }\\n  teilkultur(where: $teilkulturFilter) {\\n    id\\n    __typename\\n  }\\n  kultur(where: $kulturFilter) {\\n    id\\n    __typename\\n  }\\n  herkunft(where: $herkunftFilter) {\\n    id\\n    __typename\\n  }\\n  sammel_lieferung(where: $sammelLieferungFilter) {\\n    id\\n    __typename\\n  }\\n  lieferung(where: $lieferungFilter) {\\n    id\\n    __typename\\n  }\\n  person(where: $personFilter) {\\n    id\\n    __typename\\n  }\\n  sammlung(where: $sammlungFilter) {\\n    id\\n    __typename\\n  }\\n}\\n\"}"
    },
    "http_info": {
      "status": 200,
      "http_version": "HTTP/1.1",
      "url": "/v1/graphql",
      "ip": "77.57.29.8:54377",
      "method": "POST",
      "content_encoding": null
    }
  }
}

If I instead set the type in the .env file of docker to RS256:

HASURA_GRAPHQL_JWT_SECRET={"type":"RS256", "jwk_url": "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com", "audience": "vermehrung-f48c4", "issuer": "https://securetoken.google.com/vermehrung-f48c4"}

the error is:

{
  "type": "http-log",
  "timestamp": "2020-03-10T13:20:10.808+0000",
  "level": "error",
  "detail": {
    "operation": {
      "error": {
        "path": "$",
        "error": "Could not verify JWT: JWSError JWSInvalidSignature",
        "code": "invalid-jwt"
      },
      "request_id": "15985864-4e2f-4d35-b17d-1e061b96b67a",
      "response_size": 94,
      "raw_query": "{\"operationName\":\"TreeQueryForRoot\",\"variables\":{\"artFilter\":{\"id\":{\"_is_null\":false}},\"eventFilter\":{\"id\":{\"_is_null\":false}},\"gartenFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"kulturFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"herkunftFilter\":{\"id\":{\"_is_null\":false}},\"personFilter\":{\"id\":{\"_is_null\":false},\"aktiv\":{\"_eq\":true}},\"sammlungFilter\":{\"id\":{\"_is_null\":false}},\"lieferungFilter\":{\"id\":{\"_is_null\":false}},\"sammelLieferungFilter\":{\"id\":{\"_is_null\":false}},\"teilkulturFilter\":{\"id\":{\"_is_null\":false}},\"zaehlungFilter\":{\"id\":{\"_is_null\":false}}},\"query\":\"query TreeQueryForRoot($artFilter: art_bool_exp!, $eventFilter: event_bool_exp!, $gartenFilter: garten_bool_exp!, $kulturFilter: kultur_bool_exp!, $herkunftFilter: herkunft_bool_exp!, $personFilter: person_bool_exp!, $sammlungFilter: sammlung_bool_exp!, $teilkulturFilter: teilkultur_bool_exp!, $zaehlungFilter: zaehlung_bool_exp!, $lieferungFilter: lieferung_bool_exp!, $sammelLieferungFilter: sammel_lieferung_bool_exp!) {\\n  garten(where: $gartenFilter) {\\n    id\\n    __typename\\n  }\\n  art(where: $artFilter) {\\n    id\\n    __typename\\n  }\\n  event(where: $eventFilter) {\\n    id\\n    __typename\\n  }\\n  zaehlung(where: $zaehlungFilter) {\\n    id\\n    __typename\\n  }\\n  teilkultur(where: $teilkulturFilter) {\\n    id\\n    __typename\\n  }\\n  kultur(where: $kulturFilter) {\\n    id\\n    __typename\\n  }\\n  herkunft(where: $herkunftFilter) {\\n    id\\n    __typename\\n  }\\n  sammel_lieferung(where: $sammelLieferungFilter) {\\n    id\\n    __typename\\n  }\\n  lieferung(where: $lieferungFilter) {\\n    id\\n    __typename\\n  }\\n  person(where: $personFilter) {\\n    id\\n    __typename\\n  }\\n  sammlung(where: $sammlungFilter) {\\n    id\\n    __typename\\n  }\\n}\\n\"}"
    },
    "http_info": {
      "status": 200,
      "http_version": "HTTP/1.1",
      "url": "/v1/graphql",
      "ip": "77.57.29.8:57836",
      "method": "POST",
      "content_encoding": null
    }
  }
}

Could be related to https://github.com/hasura/graphql-engine/issues/3919 and https://github.com/hasura/graphql-engine/issues/3513.

What am I doing wrong?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:9

github_iconTop GitHub Comments

1reaction
barbalexcommented, Mar 19, 2020

@dvasdekis

The project is here: https://github.com/barbalex/vermehrung

The backend is built with docker-compose and docker. You can see it here: https://github.com/barbalex/vermehrung/tree/master/backend

The backend:

The app:

Hope this helps.

0reactions
vctqs1commented, Dec 20, 2021

I got same message, but It works well when I pass this token in Hasura console 😦

Read more comments on GitHub >

github_iconTop Results From Across the Web

Could not verify JWT: JWSError JWSInvalidSignature
I believe the issue involved mismatch access token secret key resulting in the error JWT: JWSError JWSInvalidSignature.
Read more >
JWT (JSON Web Tokens) Errors | Invalid JWT Signature
I've been working with Google Cloud products and connecting to services from my laptop like Storage and BigQuery. Over the last several months, ......
Read more >
Authentication using JWT | Hasura GraphQL Docs
Authentication using JWT. Introduction​. You can configure the GraphQL engine to use JWT authorization mode to authorize all incoming requests to the Hasura ......
Read more >
admin only operation firebase error - You.com | The AI Search ...
hasura/graphql-engine`JWSError JWSInvalidSignature`-Error on firebase#4076. Created almost 3 years ago. 9. I have a project using docker-compose:.
Read more >
无法验证令牌签名, Jwt 无效签名, 签名验证失败jwt 流明, Laravel ...
签名验证失败· 问题#40 · firebase/php-jwt · GitHub问题是,即使第一个带有ROM ... 错误:无法验证JWT:JWSError JWSInvalidSignature Hasura “Hasura 平台利用JWT ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found