Back

"Failed to verify JWT. Invalid token: Expired" when getDocument using setKey permission in nodejs

  • 0
  • Databases
  • Self Hosted
  • Web
WildAnimal
8 Apr, 2023, 02:06

Sometimes not often this error occurs.

What puzzled me was that I used the setKey method for authorization, but there was an error with JWT expiration.

Key Code Fragments:

// libs/nodeAppwrite.ts import { Client, Account, Databases, ID, Permission, Role, Query, Users, } from 'node-appwrite'

// others

const client = new Client() .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT) .setKey(process.env.APPWRITE_API_KEY) const database = new Databases(client) // others

const database = new Databases(client)

// pages/api/getDocument.ts import nodeAppwrite from '@/libs/nodeAppwrite' // others const documentRes = (await nodeappwrite.database.getDocument( process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID, process.env.NEXT_PUBLIC_APPWRITE_PAYMENTS_COLLECTION_ID, documentId )) as any // others

TL;DR
The user is getting the error "Failed to verify JWT. Invalid token: Expired" when trying to get a document using the setKey permission in Node.js. The issue seems to be that the same global `nodeAppwrite.client` instance is being used for both the login request and the getDocument request. The suggestion is to instantiate a new Client and Account instead of reusing the same instance. Additionally, it is recommended to use different clients for API key and JWT, and to use a request scoped client when using a JWT token. The exact error message is "Failed to verify JWT. Invalid token: Expired".
Drake
8 Apr, 2023, 02:16

Can you share the exact error?

Btw, it's best to use 3 back ticks with multi-line code. See https://www.markdownguide.org/extended-syntax/#syntax-highlighting

WildAnimal
8 Apr, 2023, 02:24

Yes, Some errors in docker logs:

[Error] Timestamp: 2023-04-08T02:04:44+00:00 [Error] Method: GET [Error] URL: /v1/databases/:databaseId/collections/:collectionId/documents/:documentId [Error] Type: Appwrite\Extend\Exception [Error] Message: Failed to verify JWT. Invalid token: Expired [Error] File: /usr/src/code/app/init.php [Error] Line: 865

WildAnimal
8 Apr, 2023, 02:29

And response is:

{"code":401,"type":"","response":{"code":401,"response":{"size":0,"timeout":0}}}

Drake
8 Apr, 2023, 02:29

Are you calling setJWT() anywhere?

WildAnimal
8 Apr, 2023, 02:35

Yes, I had setJWT while user login to server from client to get account info.

But the getDocument request is not a user behavior, it's a behavior similar to a web hook.

Drake
8 Apr, 2023, 02:36

Somehow the same client that had setJWT() is being used

Drake
8 Apr, 2023, 02:37

Oh...client is probably global and being reused across requests

WildAnimal
8 Apr, 2023, 02:48

Oh, what should I do.

When both methods are used simultaneously and initiated by two different clients, cannot it be distinguished.

Drake
8 Apr, 2023, 02:50

Best to use different clients with API key vs jwt. Also, make sure to use a request scoped client when using jwt token

WildAnimal
8 Apr, 2023, 03:01

I confirm that these two requests occurred on different clients. Jwt is only intended for users, while API keys are used in other situations.

Drake
8 Apr, 2023, 03:03

What's the code for setting the JWT?

WildAnimal
8 Apr, 2023, 03:05

Although it is a different client request, is it related to setKey and setJWT being executed on the same server.

Drake
8 Apr, 2023, 03:07

So that's probably why it's being reused...

WildAnimal
8 Apr, 2023, 03:13

When user request login.ts api I handle the request with iron-session:

TypeScript

import { withSessionRoute } from '@/helper/withSession'
import nodeAppwrite from '@/helper/nodeAppwrite'
import type { NextApiRequest, NextApiResponse } from 'next'

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  const { jwt, appwriteSessionId } = req.body
  if (!jwt || !appwriteSessionId) {
    res.status(401).json({ message: 'Unauthorized' })
  }
  try {
    nodeAppwrite.client.setJWT(jwt)
    await nodeAppwrite.account.get().then(
      async (response) => {
        const nowTime = Date.now()
        const newUser = {
          ...response,
          appwriteSessionId,
        }
        req.session['user'] = newUser
        req.session['jwt'] = {
          value: jwt,
          expiresAt: nowTime + 15 * 60 * 1000,
        }
        await req.session.save()
        res.send(newUser)
      },
      (error) => {
        res.status(error.code ?? 401).json({ message: error.message })
      }
    )
  } catch (error) {
    res.status(error.code ?? 500).json({ message: error.message })
  }
}
export default withSessionRoute(handler)
Drake
8 Apr, 2023, 03:14

You're importing the same global nodeAppwrite.client instance here...

Drake
8 Apr, 2023, 03:15

Try to instantiate a new Client and Account instead

WildAnimal
8 Apr, 2023, 03:19

Thank you Steven. I will try your suggestion.

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more