Serverless-application-model: Authorizers: Support AuthorizationScopes

Created on 6 Nov 2018  路  25Comments  路  Source: aws/serverless-application-model

Description:

This was brought up in Slack:

Starting to work on a PoC using the new authorizer features in SAM and already notice one huge shortcoming I didn't think about.
AuthorizationScopes - this would have been really powerful to include so I could define required scopes for authenticating tokens at the API level instead of inside the code.

This is also necessary for using access_tokens.

Docs: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html#cfn-apigateway-method-authorizationscopes

SAM should support AuthorizationScopes.

areserverless-api stagwaiting-for-release typfeature v1.20.0

Most helpful comment

This was my thread in the channel. My proposal would look something like this:

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !Ref CognitoUserPoolArn
            OAuthScopes:
              - scope1
              - scope2

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src
      Handler: lambda.handler
      MemorySize: 1024
      Runtime: nodejs8.10
      Events:
        Root:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /
            Method: GET
            Auth:
              Authorizer: MyCognitoAuthorizer
              OAuthScopes:
                - scope3

This is a swagger doc from one of my templates to show what it looks like with scopes defined:

ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      EndpointConfiguration: EDGE

      DefinitionBody:
        swagger: 2.0
        info:
          title: !Ref AWS::StackName
        securityDefinitions:
          CognitoAuth:
            type: apiKey
            name: Authorization
            in: header
            x-amazon-apigateway-authtype: cognito_user_pools
            x-amazon-apigateway-authorizer:
              type: cognito_user_pools
              providerARNs:
                - !Ref CognitoUserPoolArn

        paths:
          "/messages":
            post:
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SendMessage.Arn}/invocations
              responses: {}
              security:
                - CognitoAuth:
                  - "rds-worker/send_message"

          "/errors":
            get:
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Errors.Arn}/invocations
              responses: {}
              security:
                - CognitoAuth:
                  - "rds-worker/read_errors

Edit: Noticed a bad indent.

All 25 comments

This was my thread in the channel. My proposal would look something like this:

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !Ref CognitoUserPoolArn
            OAuthScopes:
              - scope1
              - scope2

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src
      Handler: lambda.handler
      MemorySize: 1024
      Runtime: nodejs8.10
      Events:
        Root:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /
            Method: GET
            Auth:
              Authorizer: MyCognitoAuthorizer
              OAuthScopes:
                - scope3

This is a swagger doc from one of my templates to show what it looks like with scopes defined:

ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      EndpointConfiguration: EDGE

      DefinitionBody:
        swagger: 2.0
        info:
          title: !Ref AWS::StackName
        securityDefinitions:
          CognitoAuth:
            type: apiKey
            name: Authorization
            in: header
            x-amazon-apigateway-authtype: cognito_user_pools
            x-amazon-apigateway-authorizer:
              type: cognito_user_pools
              providerARNs:
                - !Ref CognitoUserPoolArn

        paths:
          "/messages":
            post:
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SendMessage.Arn}/invocations
              responses: {}
              security:
                - CognitoAuth:
                  - "rds-worker/send_message"

          "/errors":
            get:
              x-amazon-apigateway-integration:
                httpMethod: post
                type: aws_proxy
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Errors.Arn}/invocations
              responses: {}
              security:
                - CognitoAuth:
                  - "rds-worker/read_errors

Edit: Noticed a bad indent.

Leaving this issue open for +1's and further comments. Happy to work with anyone that wants to implement this feature.

+1
I find it quite an important feature to use the full power of OAuth and Cognito.

Is there any plan to include this feature in the near future?

I can look into implementing this. The transformation to swagger is simple enough, although I'm not sure if there are other steps that need to be implemented.
In any case, what would be the expected behavior when only a scope is specified? Without an authorizer like this:

MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !Ref CognitoUserPoolArn
              OAuthScopes:
                - scope1
                - scope2

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src
      Handler: lambda.handler
      MemorySize: 1024
      Runtime: nodejs8.10
      Events:
        Root:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /
            Method: GET
            Auth:
              OAuthScopes:
                - scope3

I would propose choosing the default authorizer in this case.

I also want to propose calling it AuthorizationScopes instead of OAuthScopes since it is more consistent with the naming of the AWS::ApiGateway::Method in normal CloudFormation.
Or is it better to make the naming different to ensure there is no mix up for inexperienced users?

@klmz Keeping the naming the same should be fine. I think the transformation into swagger + some supporting tests are all that are needed for this feature, correct me if I'm wrong.

Yes, that is what I figured. I got most of it working. Is there any documentation on what is expected in terms of tests? I saw some end-to-end test that will be needed, anything else?

@klmz we don't have any docs on what is expected for tests, but I would recommend some end-to-end tests like you suggested, as well as some tests for the new swagger that is generated in https://github.com/awslabs/serverless-application-model/blob/develop/tests/swagger/test_swagger.py.

I would propose choosing the default authorizer in this case.

This is correct. Looking forward to the PR!

How long would it be until this get pushed in with the next release !? +1

@MohammedAlSafwan We are still working on reviewing the PR, once that's reviewed and merged in we will assign a release tag on it.

@praneetap ... thank you, I just noticed that it had conflict... I really hope that could be done soon

Looking forward to having this functionality!

+1 on looking forward to this functionality - having to work round this was a pain today. Any ETA on the release?

I've been looking into this (both fixing merge conflicts in the code and the actual spec).

Using scopes in method authorization for Cognito is possible as per APIGW Cognito Docs, and is also consistent with the example shared by @brysontyrrell

This issue is for scopes on methods using Cognito auth, and does not address adding generic OAuth 2.0 support yet.

Some existing questions:

  1. With the current proposal (included below for reference), would scopes scope1 and scope2 be applied to all methods using MyCognitoAuthorizer, meaning that the root event would have scope1, scope2, and scope3 as scopes?
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: MyCognitoAuthorizer
        Authorizers:
          MyCognitoAuthorizer:
            UserPoolArn: !Ref CognitoUserPoolArn
              OAuthScopes:
                - scope1
                - scope2

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src
      Handler: lambda.handler
      MemorySize: 1024
      Runtime: nodejs8.10
      Events:
        Root:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /
            Method: GET
            Auth:
              Authorizer: MyCognitoAuthorizer
              OAuthScopes:
                - scope3

@keetonian : logically, yes :)
I can't wait to use this !

@keetonian @David-V2 That was the intent of my original example, but it might be more appropriate to have that be a part of Globals:

Globals:
  Function:
    Auth:
      OAuthScopes:
        - scope-1
        - scope-2

Note that Auth is not yet listed as a supported value in Globals.

Any pointers on ETA of this feature ?

I know that I'm asking again about this feature and I know that you guys are working hard. The feature is related to [WIP] Add authorizationscopes #917. The reason why I'm asking is because we are in need of defining a scope so that we are able to use Access Token instead of ID Token through the API Gateway. is there any solution around the problem other than adding the scope manually to every API method?

Unfortunately, I will not have time to work on this in the foreseeable future. It shouldn't be super hard to complete this PR though, so feel free to complete it.

@klmz ... thank you so much for letting us know. It would be nice if [WIP] Add authorizationscopes #917 get moved to "To do" or removed so people don't get confused. Thank you so much for your effort.

Updated the PR, should get this merged soon!

Is there any chance v1.20.0 is going to be released this week?

Is there any chance v1.20.0 is going to be released this week?

Just updated the tracker. We are deploying in multiple regions right now. We should be releasing early next week, if everything goes okay!

Was this page helpful?
0 / 5 - 0 ratings