Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(httpApi): external authorizer #7789

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion docs/providers/aws/events/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,64 @@ provider:
id: xxxx # id of externally created HTTP API to which endpoints should be attached.
```

In such case no API and stage resources are created, therefore extending HTTP API with CORS or access logs settings is not supported.
In such case no API and stage resources are created, therefore extending HTTP API with CORS, access logs settings or authorizers is not supported.

## Shared Authorizer

For external HTTP API you can use shared authorizer in similar manner to RestApi. Example configuration could look like:

```yml
httpApi:
id: xxxx # Required

functions:
createUser:
...
events:
- httpApi:
path: /users
...
authorizer:
# Provide authorizerId
id:
Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID
scopes: # Optional - List of Oauth2 scopes
- myapp/myscope

deleteUser:
...
events:
- httpApi:
path: /users/{userId}
...
authorizer:
# Provide authorizerId
id:
Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID
scopes: # Optional - List of Oauth2 scopes
- myapp/anotherscope

resources:
Resources:
ApiGatewayAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
ApiId:
Ref: YourApiGatewayName
AuthorizerType: JWT
IdentitySource:
- $request.header.Authorization
JwtConfiguration:
Audience:
- Ref: YourCognitoUserPoolClientName
Issuer:
Fn::Join:
- ""
- - "https://cognito-idp."
- "${opt:region, self:provider.region}"
- ".amazonaws.com/"
- Ref: YourCognitoUserPoolName
```

### Event / payload format

Expand Down
32 changes: 27 additions & 5 deletions lib/plugins/aws/package/compile/events/httpApi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ class HttpApiEvents {
DependsOn: this.provider.naming.getHttpApiIntegrationLogicalId(targetData.functionName),
});
if (authorizer) {
const { id } = authorizer;
Object.assign(resource.Properties, {
AuthorizationType: 'JWT',
AuthorizerId: {
AuthorizerId: id || {
Ref: this.provider.naming.getHttpApiAuthorizerLogicalId(authorizer.name),
},
AuthorizationScopes: authorizationScopes && Array.from(authorizationScopes),
Expand All @@ -188,7 +189,7 @@ Object.defineProperties(
if (userCors) {
if (userConfig.id) {
throw new this.serverless.classes.Error(
'Cannot setup CORS rules for externally confugured HTTP API',
'Cannot setup CORS rules for externally configured HTTP API',
'EXTERNAL_HTTP_API_CORS_CONFIG'
);
}
Expand Down Expand Up @@ -217,6 +218,12 @@ Object.defineProperties(
const userAuthorizers = userConfig.authorizers;
const authorizers = (this.config.authorizers = new Map());
if (userAuthorizers) {
if (userConfig.id) {
throw new this.serverless.classes.Error(
'Cannot setup authorizers for externally configured HTTP API',
'EXTERNAL_HTTP_API_AUTHORIZERS_CONFIG'
);
}
for (const [name, authorizerConfig] of _.entries(userAuthorizers)) {
authorizers.set(name, {
name: authorizerConfig.name || name,
Expand Down Expand Up @@ -351,17 +358,32 @@ Object.defineProperties(
}
const routeConfig = { targetData: routeTargetData };
if (authorizer) {
const { name, scopes } = (() => {
const { name, scopes, id } = (() => {
if (_.isObject(authorizer)) return authorizer;
return { name: authorizer };
})();
if (!authorizers.has(name)) {
if (id) {
Michsior14 marked this conversation as resolved.
Show resolved Hide resolved
if (!userConfig.id) {
throw new this.serverless.classes.Error(
`Event references external authorizer '${id}', but httpApi is part of the current stack.`,
'EXTERNAL_HTTP_API_AUTHORIZER_WITHOUT_EXTERNAL_HTTP_API'
);
}
if (name) {
throw new this.serverless.classes.Error(
`Event references external authorizer and provide a local name property in function ${functionName}.`,
Michsior14 marked this conversation as resolved.
Show resolved Hide resolved
'EXTERNAL_HTTP_API_AUTHORIZER_NAME_PROVIDED'
);
}
routeConfig.authorizer = { id };
} else if (!authorizers.has(name)) {
throw new this.serverless.classes.Error(
`Event references not configured authorizer '${name}'`,
'UNRECOGNIZED_HTTP_API_AUTHORIZER'
);
} else {
routeConfig.authorizer = authorizers.get(name);
}
routeConfig.authorizer = authorizers.get(name);
if (scopes) routeConfig.authorizationScopes = toSet(scopes);
}
if (!timeout) timeout = userConfig.timeout || null;
Expand Down
Loading