Sign In Methods
Custom JWTs
Creating custom JWTs
In some cases, it’s necessary to act on behalf of a user. While the Auth service doesn’t support this directly, it’s not difficult to implement using a serverless function. Below is an example of a function that generates a valid access token for your application with customized values. For details, see the function’s docstring.
Feel free to adapt to your needs.
Dependencies
Copy
Ask AI
npm install jsonwebtoken
Function
Create a file under functions
(for instance /functions/custom-jwts.ts
), with the following contents:
Copy
Ask AI
import { Request, Response } from 'express'
import process from 'process'
import jwt from 'jsonwebtoken'
// function to extract jwt from the request
const getJwt = (req: Request): string | null => {
const authHeader = req.headers.authorization
if (!authHeader) {
return null
}
const parts = authHeader.split(' ')
if (parts.length !== 2) {
return null
}
const [scheme, token] = parts
if (!/^Bearer$/i.test(scheme)) {
return null
}
return token
}
// validate jwt token is valid and caller is either an admin or an operator
const jwtIsAuthorized = (req: Request, key: string): string => {
const token = getJwt(req)
if (!token) {
return ""
}
try {
const decoded = jwt.verify(token, key)
const claims = decoded['https://hasura.io/jwt/claims']
if ( !claims || !claims['x-hasura-allowed-roles'] ) {
return ""
}
if (
claims['x-hasura-allowed-roles'].includes('admin') ||
claims['x-hasura-allowed-roles'].includes('operator')
) {
return decoded.sub
}
return ""
} catch (e) {
return ""
}
}
/*
This is a sample function that generates a JWT token to impersonate users.
Authorization:
- send a valid JWT token with the request. The token should have the `admin` or `operator` role.
- send the `x-hasura-admin-secret` header with the request
Body:
A json object with the following keys:
- `userId` (string): the user id for which the token is generated
- `defaultRole` (string): the default role for the userId
- `allowedRoles` (array of strings): the roles that the userId can assume
Returns:
A json object with the following keys:
- `accessToken` (string) - The generated access token
In addition to the typical JWT claims generated by Nhost, the token generated by this function will have the following claims:
- `x-hasura-on-behalf-of`: the user id of the caller or `admin` if the caller used the `x-hasura-admin-secret` header
You are free to modify this function to suit your needs.
*/
export default (req: Request, res: Response) => {
let authorizedCaller = ""
if (req.headers['x-hasura-admin-secret'] === process.env.HASURA_GRAPHQL_ADMIN_SECRET) {
authorizedCaller = "admin"
}
const jwtSecret = JSON.parse(process.env.NHOST_JWT_SECRET)
if (!authorizedCaller) {
authorizedCaller = jwtIsAuthorized(req, jwtSecret.key)
}
if (!authorizedCaller) {
return res.status(401).json({ message: 'Unauthorized' })
}
// extract from json in the body
const {userId, defaultRole, allowedRoles} = req.body
if (!userId || !defaultRole || !allowedRoles) {
return res.status(400).json({ message: 'Bad request' })
}
let token = jwt.sign({
"exp": Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour
"https://hasura.io/jwt/claims": {
"x-hasura-allowed-roles": allowedRoles,
"x-hasura-default-role": defaultRole,
"x-hasura-user-id": userId,
"x-hasura-user-is-anonymous": "false",
"x-hasura-on-behalf-of": authorizedCaller
},
"iat": Math.floor(Date.now() / 1000),
"iss": "custom-lambda",
"sub": userId,
}, jwtSecret.key);
res.status(200).json(
{
accessToken: token,
},
)
}
Now you can call it like:
Copy
Ask AI
curl -X POST \
-H "Content-Type: application/json" \
-H "x-hasura-admin-secret: nhost-admin-secret" \
-d '{"userId": "FFAB5354-C5EB-42C1-8BC3-AD21D2297883", "defaultRole": "user", "allowedRoles": ["user", "me"]}' \
https://local.functions.local.nhost.run/v1/custom-jwt
{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTcxNDIyMTMsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJ1c2VyIiwibWUiXSwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLXVzZXItaWQiOiJGRkFCNTM1NC1DNUVCLTQyQzEtOEJDMy1BRDIxRDIyOTc4ODMiLCJ4LWhhc3VyYS11c2VyLWlzLWFub255bW91cyI6ImZhbHNlIiwieC1oYXN1cmEtb24tYmVoYWxmLW9mIjoiYWRtaW4ifSwiaWF0IjoxNzE3MTM4NjEzLCJpc3MiOiJjdXN0b20tbGFtYmRhIiwic3ViIjoiRkZBQjUzNTQtQzVFQi00MkMxLThCQzMtQUQyMUQyMjk3ODgzIn0.bRhzJvXMdkQA8aXPH95uMT17WHED2rSRq3gE21Vp3Ak"}
The new token should be a valid token for your application with the custom values requested:
Copy
Ask AI
{
"exp": 1717141288,
"https://hasura.io/jwt/claims": {
"x-hasura-allowed-roles": ["a", "b"],
"x-hasura-default-role": "user",
"x-hasura-user-id": "FFAB5354-C5EB-42C1-8BC3-AD21D2297883",
"x-hasura-user-is-anonymous": "false",
"x-hasura-on-behalf-of": "admin"
},
"iat": 1717137688,
"iss": "custom-lambda",
"sub": "FFAB5354-C5EB-42C1-8BC3-AD21D2297883"
}
Was this page helpful?
On this page
Assistant
Responses are generated using AI and may contain mistakes.