serverless-http
serverless-http copied to clipboard
How to access context value from Lambda Authorizer?
I am trying to pass some data to backend using lambda authorizer, something like this
{
"principalId": "xxxxxxxx", // The principal user identification associated with the token send by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow|Deny",
"Resource": "arn:aws:execute-api:<regionId>:<accountId>:<appId>/<stage>/<httpVerb>/[<resource>/<httpVerb>/[...]]"
}
]
},
"context": {
"key": "value",
"numKey": 1,
"boolKey": true
}
}
However i am not able to understand; how to fetch this using below code
const handler = serverless(app);
module.exports.handler = async (event, context) => {
// you can do other things here
const result = await handler(event, context);
// and here
return result;
};
I want a way where i can access that in my backend and pass on to my routes
+1
Oops! still open
✅ A bit late, but I finally found a solution for this without any extra lib or custom code!
You can access details of the raw Lambda request under ctx.req
and there is a field called apiGateway
. Here you can find the original AWS Request (event
and context
). Because I'm using typescript, I had some typing issues and was forced to explicit type the ctx.req
as any
. The following code works for me
const orgReq = ctx.req as any;
const awsRequest = orgReq.apiGateway; // { event: {...}, context: {...}}
const lambdaContext = awsRequest.context;
console.debug(JSON.stringify(lambdaContext));
const orgReq = ctx.req as any;
This works, but if you want to skip the any... make a type.d.ts file and add
declare namespace Express {
export interface Request {
apiGateway: {
event: APIGatewayProxyEvent,
context:
APIGatewayEventRequestContextWithAuthorizer<APIGatewayEventLambdaAuthorizerContext<TAuthorizerContext>>;
}
}
}
Context is a little trickier because it does really depend on what you're using. This works for custom authorizers so you can do req.apiGateway.context.authorizer
now without issue.
OK, so to put things together, here's my near-complete approach.
I have a main entry point in my index.ts
where I set up my middleware, routes, etc. Each route handler is then in a separate module, coming from a factory function. Authorizer data in my case includes: user ID, user handle, and user name. In order to access the data, serverless-http
must be aware that data of such shape will be present in the original request context, and it needs to extend the original Express request. This is how I've done it:
/**
* /index.ts
*/
import { Request } from 'express';
import indexHandlerFactory from './handlers/index';
const app = express();
// Set up middleware.
app.use(cors());
// Set up routing.
app.get('/', indexHandlerFactory());
export const handler = serverless(app, {
// Transform all incoming requests - assign authorizer data from Lambda request context.
request (request: Request, event: APIGatewayProxyEvent) {
// AuthorizerContext describes the shape of my user data and is defined in my type.d.ts.
request.auth = event.requestContext.authorizer as AuthorizerContext;
},
});
/**
* type.d.ts
*/
type AuthorizerContext = {
userId: number;
userHandle: string;
userName: string;
}
// Declaration merging
declare namespace Express {
export interface Request {
auth: AuthorizerContext;
}
}
/**
* ./handlers/index.ts
*/
import { Request, Response } from 'express';
export default function indexHandlerFactory() {
return async (req: Request, res: Response): Promise<Response> => {
const { userId, userName, userHandle } = req.auth;
}
}
More on request & response transformations: https://github.com/dougmoscrop/serverless-http/blob/master/docs/ADVANCED.md#transformations SO answer on declaration merging: https://stackoverflow.com/a/40762463/210327 TS docs on declaration merging: https://www.typescriptlang.org/docs/handbook/declaration-merging.html