表題の通りです。苦しめられたので解決方法を共有します。
ポイントとしては、
- プリフライト用にOPTIONSメソッドを受け入れる必要がある (Access-Control系のヘッダーも返す)
- AWS::Serverless::ApiのCorsプロパティを定義すれば、自動的にOPTIONSメソッドが作成され設定したヘッダーが返されるようになる
- CorsConfiguration - AWS Serverless Application Model
- LambdaでAccess-Control系のヘッダーを返す
- 普通にレスポンスにヘッダーを含めればOK
- ↓「Lambda または HTTP プロキシ統合への CORS のサポートを有効にする」の項目を参照
- REST API リソースの CORS を有効にする - Amazon API Gateway
- 400系、500系の場合のレスポンスヘッダーはGatewayResponseで設定すれば良い
ハマりどころとしては、
- Corsプロパティを定義する際、AWS::Serverless::ApiのAuthプロパティで、AddDefaultAuthorizerToCorsPreflightをfalse(デフォルトでtrue)にしない限り、プリフライトのOPTIONSメソッドにまでLambda Authorizerが介入してしまう
- プリフライトの送信内容はこちらで制御できないため、ほぼ確実にAuthorizerで弾かれてしまう
- 弾かれたときにAccess-Control系ヘッダーを返しても、ステータスコード200以外は認められない
- Lambda AuthorizerでOPTIONSメソッドのときだけ無条件で200を返してもいいが、AddDefaultAuthorizerToCorsPreflightをfalseにした方が色々スマート
一応サンプルのtemplate.ymlを残しておきます。
template.yml
ResourceApi:
Type: AWS::Serverless::Api
Properties:
StageName: v1
Cors:
AllowMethods: "'GET'"
AllowHeaders: "'authorization'"
AllowOrigin: "'*'"
MaxAge: "'180'"
GatewayResponses:
DEFAULT_4XX:
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'GET'"
Access-Control-Allow-Headers: "'authorization'"
Access-Control-Allow-Origin: "'*'"
Access-Control-Max-Age: "'180'"
DEFAULT_5XX:
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'GET'"
Access-Control-Allow-Headers: "'authorization'"
Access-Control-Allow-Origin: "'*'"
Access-Control-Max-Age: "'180'"
Auth:
AddDefaultAuthorizerToCorsPreflight: false
DefaultAuthorizer: LambdaRequestAuthorizer
Authorizers:
LambdaRequestAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn: !GetAtt checkTokenFunction.Arn
Identity:
Headers:
- Authorization
ReauthorizeEvery: 0