Eelco
05/06/2025, 3:54 PMts
const payload = {
orgId: process.env.VAPI_ORG_ID,
// This is the scope of the token
token: {
tag: 'public',
restrictions: {
enabled: process.env.NODE_ENV !== 'development',
allowedOrigins: [process.env.NEXT_PUBLIC_APP_URL],
allowedAssistantIds: [assistant.vapiId],
allowTransientAssistant: false,
},
},
}
// Get the private key from environment variables
const key = new TextEncoder().encode(process.env.VAPI_PRIVATE_KEY)
// Generate the token using a JWT library or built-in functionality
const token = await new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setExpirationTime('1h')
.sign(key)
The JWT validates correctly using the private key, however from the vapi api we receive:
{
"message": "Couldn't verify JWT.",
"error": "Unauthorized",
"statusCode": 401
}
It would really help if the docs were complete and include working demo's or examples.Vapi Support Bot
05/06/2025, 3:56 PMts
// Make sure you're using the correct private key format
// Vapi might be expecting a different format than what you're providing
const key = process.env.VAPI_PRIVATE_KEY
.replace(/\\n/g, '\n') // Handle any escaped newlines
.trim();
// Then use it without TextEncoder
const token = await new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setExpirationTime('1h')
.sign(Buffer.from(key, 'utf-8')) // Or appropriate format
You can also verify your JWT at [jwt.io](https://jwt.io) to ensure it's correctly formatted.
Sources:
- [Discord message about JWT validation failures](https://discord.com/channels/1211482211119796234/1336360744916226168)
- [Discord message about troubleshooting JWT issues](https://discord.com/channels/1211482211119796234/1336414771309838448)Kings_bigđź’«
05/06/2025, 6:03 PMEelco
05/06/2025, 7:37 PMdimitridb
05/07/2025, 6:37 AMChiranjeet Mishra
05/10/2025, 10:44 PMgtr
05/12/2025, 5:16 AMgtr
05/12/2025, 5:20 AMChiranjeet Mishra
05/14/2025, 10:26 PMtoken object and the correct scope (public or private), as missing scopes can lead to issues. If you continue experiencing issues, check your environment variables to ensure ORG_ID and PRIVATE_KEY are accurately set. If you need any more help, feel free to ask.Eelco
05/21/2025, 2:06 PMEelco
05/21/2025, 2:06 PMChiranjeet Mishra
05/22/2025, 4:30 AMconst jwt = require('jsonwebtoken'); // Switch to jsonwebtoken
// Clean any potential formatting issues in the key
const privateKey = process.env.VAPI_PRIVATE_KEY.trim();
const payload = {
orgId: process.env.VAPI_ORG_ID,
token: {
tag: 'public',
restrictions: {
enabled: true,
allowedOrigins: [process.env.NEXT_PUBLIC_APP_URL],
allowedAssistantIds: [assistant.vapiId],
allowTransientAssistant: false,
},
}
};
// Use same library/approach as Vapi backend
const token = jwt.sign(payload, privateKey, {
algorithm: 'HS256',
expiresIn: '1h'
});
This approach matches Vapi's internal JWT generation and verification exactly as required.Chiranjeet Mishra
05/22/2025, 4:30 AMEelco
05/29/2025, 7:59 AMChiranjeet Mishra
05/29/2025, 9:28 PM