I'm trying to find a way to allow guest mode in custom authorizer in AWS.
Basically, what I want to achieve is the following scenario:
Authorization
header in request then trigger lambda function that responds with some dataAuthorization
header then my custom authorizer should check JWT token and either Allow
or Deny
. Then trigger lambda if custom-authorizer
returned Allow
I see I can achieve either but not both, i.e. I can open the endpoint (remove authorizer
completely) which works okay or I can put authorizer
which again works okay.
Yet, I don't see a way to by-pass custom-authorizer
when there is no Authorization
header.
Example configuration in serverless:
functions:
hello:
handler: handler.hello
events:
- http:
path: /hello
method: get
private: true
authorizer:
identitySource: method.request.header.Authorization # Can this be optional?
name: custom-authorizer
custom-authorizer:
handler: authorizer.handler
From my testing I can confirm that once authorization
is there and there is no Authorization
header in request then my custom-authorizer
is not triggered at all and API gateway responds straight away with 401 Unauthorized
.
Please take into account that in my guest mode I don't want to get custom API gateway response (this is possible and works). I want to trigger lambda function just like there was no authorization at all.
I'm coming to conclusion this is impossible and the only workaround is to remove authorization
and then do some custom code in lambda.
Any advice?
Following up on @fedonev answer here is the complete solution:
HTTP API
instead of REST API
.custom-authorizer
Let's start with updating serverless.yml
accordingly to the newer and different HTTP API syntax:
Replace events.http
with events.httpApi
and add httpApi.authorizer
to provider
. Updated serverless.yml
:
provider:
httpApi: # Added
authorizers:
customAuthorizer:
type: request
functionName: custom-authorizer
functions:
hello:
handler: handler.hello
events:
- httpApi: # Changed
path: /hello
method: get
authorizer:
name: customAuthorizer # Changed
custom-authorizer:
handler: authorizer.handler
Next, we need to update our authorizer handler function as well. It still needs to return policy as it was doing with REST API. Yet... there is no event.authorizationToken
and no event.methodArn
anymore (I left it commented out for reference):
module.exports.handler = async (event) => {
if (
!event.headers.authorization ||
event.headers.authorization === 'Bearer ABCDEF'
) {
// if (event.authorizationToken === 'Bearer ABCDEF')
return {
principalId: 'anonymous',
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: 'Allow',
Resource: event.routeArn,
// Resource: event.methodArn,
},
],
},
};
}
throw Error('Unauthorized');
};
Now, we can see we have a full control over authorization and we can check if the token is there: !event.headers.authorization
(this simulates guest mode) or if token is valid: event.headers.authorization === 'Bearer ABCDEF'
. If the token is invalid we throw error which gives 401 Unauthorized
as expected.
Finally, worth noting is that all headers
keys are lowercased and principalId
is mandatory (as previously, when using REST API, authorizer worked without it).
Deploy and enjoy!