Using Lambda Authorizer To Grant Access To GET Or POST Requests Based On API Key

Vinayak Pandey
AWS Tip
Published in
5 min readMar 18, 2024

--

When there are multiple API keys associated with a usage plan, you can use Lambda Authorizer to grant some API keys to make only GET requests while the other API keys can make GET and POST requests. In this post, we’ll see how to implement this.

Step 1: Go to API Gateway and create an example REST API.

Deploy the API to a stage named dev.

Step 2: Create 2 API keys named readonly and fullaccess.

and a Usage plan. Add both the keys to this usage plan.

and associate this Usage plan with the dev stage of PetStore API.

Step 3: Execute following commands to make sure API is working fine. Replace values for <APIGW_ID> and <REGION> accordingly.

curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev 
curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets
curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets/1
curl -X POST https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets -H "Content-Type: application/json" -d '{"type": "Bird", "price": 3,"id":4}'

Step 4: Set API key required to True for GET and POST request for /pets and GET request for {petId}.

Deploy the API.

Step 5: Execute following commands to make sure API is working fine. Replace values for <APIGW_ID> and <REGION> accordingly. For <API_KEY> you may use readonly or fullaccess key that we created.

curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev # Will work fine
curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets # Will be Forbidden
curl https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets/1 #Will be Forbidden
curl -X POST https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets -H "Content-Type: application/json" -d '{"type": "Bird", "price": 3,"id":4}' #Will be Forbidden

curl -H 'x-api-key: <API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets # Will work fine
curl -H 'x-api-key: <API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets/1 # Will work fine
curl -X POST -H 'x-api-key: <API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets -H "Content-Type: application/json" -d '{"type": "Bird", "price": 3,"id":4}' # Will work fine

Step 6: Create a Lambda function named custom_authorizer using Python 3.11 runtime. Use following code(original code given at https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html#api-gateway-lambda-authorizer-create)

Specify values for READ_ONLY_API_KEY and FULL_ACCESS_API_KEY.

# A simple request-based authorizer example to demonstrate how to use request
# parameters to allow or deny a request. In this example, a request is
# authorized if the client-supplied headerauth1 header, QueryString1
# query parameter, and stage variable of StageVar1 all match
# specified values of 'headerValue1', 'queryValue1', and 'stageValue1',
# respectively.

import json
import random, string

READ_ONLY_API_KEY=''
FULL_ACCESS_API_KEY=''


def lambda_handler(event, context):
print(event)

# Retrieve request parameters from the Lambda function input:
headers = event['headers']
queryStringParameters = event['queryStringParameters']
pathParameters = event['pathParameters']
stageVariables = event['stageVariables']

# Parse the input for the parameter values
tmp = event['methodArn'].split(':')
apiGatewayArnTmp = tmp[5].split('/')
awsAccountId = tmp[4]
region = tmp[3]
restApiId = apiGatewayArnTmp[0]
stage = apiGatewayArnTmp[1]
method = apiGatewayArnTmp[2]
resource = '/'

if (apiGatewayArnTmp[3]):
resource += apiGatewayArnTmp[3]

# Perform authorization to return the Allow policy for correct parameters
# and the 'Unauthorized' error, otherwise.

authResponse = {}
condition = {}
condition['IpAddress'] = {}

if headers['x-api-key'] == READ_ONLY_API_KEY and event['httpMethod'] == 'GET':
response = generateAllow('me', event['methodArn'])
print('authorized')
return json.loads(response)
elif headers['x-api-key'] == FULL_ACCESS_API_KEY:
response = generateAllow('me', event['methodArn'])
print('authorized')
return json.loads(response)
else:
print('unauthorized')
raise Exception('Unauthorized') # Return a 401 Unauthorized response
return 'unauthorized'

# Help function to generate IAM policy


def generatePolicy(principalId, effect, resource):
authResponse = {}
authResponse['principalId'] = principalId
if (effect and resource):
policyDocument = {}
policyDocument['Version'] = '2012-10-17'
policyDocument['Statement'] = []
statementOne = {}
statementOne['Action'] = 'execute-api:Invoke'
statementOne['Effect'] = effect
statementOne['Resource'] = resource
policyDocument['Statement'] = [statementOne]
authResponse['policyDocument'] = policyDocument

authResponse['context'] = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": True
}

authResponse_JSON = json.dumps(authResponse)
print(authResponse_JSON)

return authResponse_JSON


def generateAllow(principalId, resource):
return generatePolicy(principalId, 'Allow', resource)


def generateDeny(principalId, resource):
return generatePolicy(principalId, 'Deny', resource)

Step 7: Go to Authorizer->Create authorizer and create a custom authorizer named custom_authorizer with Lambda as authorizer type and specify the Lambda we created in Step 6.

Make sure to disable Authorization caching

Step 8: Set Authorisation to custom_authorizer for GET and POST request for /pets and GET request for {petId}.

Deploy the API.

Step 9: Now execute following commands to make sure everything is working as expected.

curl -H 'x-api-key: <READ_ONLY_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets # Will Work fine

curl -H 'x-api-key: <READ_ONLY_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets/1 # Will Work fine

curl -X POST -H 'x-api-key: <READ_ONLY_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets -H "Content-Type: application/json" -d '{"type": "Bird", "price": 3,"id":4}' #Will get unauthorized error

curl -H 'x-api-key: <FULL_ACCESS_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets # Will Work fine

curl -H 'x-api-key: <FULL_ACCESS_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets/1 # Will Work fine

curl -X POST -H 'x-api-key: <FULL_ACCESS_API_KEY>' https://<APIGW_ID>.execute-api.<REGION>.amazonaws.com/dev/pets -H "Content-Type: application/json" -d '{"type": "Bird", "price": 3,"id":4}' # Will Work fine

Now readonly API key will work only with GET requests while fullaccess API key will work with GET and POST requests.

--

--