examples
examples copied to clipboard
Websocket authorzation handler - return something that isn't `500`?
Question / help needed
I'm trying to get authorization working before connecting to websockets, which works, but I'm struggling to return an error message that isn't 500
.
I've managed to make an auth handler, like so:
connectHandler: {
handler: 'handler.connectHandler',
events: [
{
"websocket": {
route: "$connect",
authorizer: {
name: "authHandler",
identitySource: [
// No identity source, leave it up to the handler
],
},
},
},
],
environment: {
// ..
},
},
Any my authHandler
:
export const authHandler = async (event, _context) => {
console.log('🔑 Auth request received', event.requestContext)
const token = event.headers.Authorization ?? event.queryStringParameters.Authorization;
console.log('Token:', token)
if (token !== 'secret') {
return {
statusCode: 401,
}
}
return {
"principalId": "user",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": event.methodArn
}
]
}
};
}
Questions:
-
what should I return in case of an error? Any request to my websocket-server that doesn't have the
secret
header/querystring returns500
right now, and I'd prefer it to return a4xx
status code. -
what is the correct type for the authorization handler? I'm using
APIGatewayProxyHandler
on the other fn handlers which gives me nice inline errors.How my other handlers look like, which gives me pleasant TypeScript-errors when I do something wrong
```tsexport const connectHandler: APIGatewayProxyHandler = async (event, _context) => { const connectionId = event.requestContext.connectionId!
console.log('➕ Adding connection ', connectionId)
await client.query('INSERT INTO "public"."Connection"("id") VALUES($1) RETURNING *', [connectionId]) return { statusCode: 200, body: '', }; }
</details>
I managed do get 4xx
working by letting the user "slip through" the auth handler, which doesn't feel great, but it works --
If the connect-handler returns 401 it actually propagates to the connecting client
type AuthContext = {
authorized: '0'; // this would be a `boolean`, but seems like AWS stringifies boolean values of the ctx
} | {
authorized: '1';
token: string;
}
export const connectHandler: APIGatewayProxyWithLambdaAuthorizerHandler<AuthContext> = async (event, _context) => {
const connectionId = event.requestContext.connectionId!
if (event.requestContext.authorizer.authorized !== '1') {
return {
statusCode: 401,
body: ''
}
}
console.log('➕ Adding connection ', connectionId)
await client.query('INSERT INTO "public"."Connection"("id") VALUES($1) RETURNING *', [connectionId])
return {
statusCode: 200,
body: '',
};
}
export const authHandler: APIGatewayRequestAuthorizerWithContextHandler<AuthContext> = async (event, _context) => {
console.log('🔑 Auth request received', event.requestContext)
const token = event.headers.Authorization ?? event.queryStringParameters.Authorization;
console.log('Token:', token)
const result = {
"principalId": "user",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": '*'
}
]
}
}
if (token !== 'secret') {
return {
...result,
context: {
authorized: '0',
}
};
}
return {
...result,
context: {
authorized: '1',
token,
}
};
}