swift-aws-lambda-runtime icon indicating copy to clipboard operation
swift-aws-lambda-runtime copied to clipboard

Lambda Authorizer - APIGateway.Request

Open rmickeyd opened this issue 4 years ago • 8 comments

Expected behavior

Obtain information passed from a Lambda Authorizer into Lambda.

Note: This is the REST API (V1)

Actual behavior

Inability to access information due to parameter not existing on APIGateway.Request

If possible, minimal yet complete reproducer code (or URL to code)

{
...
"requestContext": {
      "authorizer": {
        "principalId": "user-id",
        "integrationLatency": 557
      }
}
...
}

Maybe it makes sense to add this to APIGateway.Request.

public let authorizer: Authorizer?

public struct Authorizer: Codable {
    public let principalId: String
    public let context: [String: String]?
}

// OR

public let authorizer: [String: String]?

rmickeyd avatar Jul 28 '20 20:07 rmickeyd

thanks for reporting @rmickeyd ~is this issue while using lambda vi api gateway?~ is this the feature you are referring to?

wdyt @fabianfett

tomerd avatar Jul 30 '20 04:07 tomerd

@tomerd yes, this is the feature. Decoding might not be straight forward though. It seems when you generate an IAM policy you set a principalId which seems to always be present and then user defined attributes. The issue is AWS sends this all lumped together in one container like so:

"requestContext": {
      "authorizer": {
        "principalId": "user-id",
        "integrationLatency": 557,
        "userDefinedString": "stringval",
        "userDefinedNumber": 123,
        "userDefinedBool": true
      }
}

rmickeyd avatar Jul 30 '20 04:07 rmickeyd

I see. any ideas on how to do this generically or should it be left as exercise for the Lambda author?

tomerd avatar Aug 06 '20 21:08 tomerd

imo the critical piece of information is the principalId. This is what should identify the user that made the authenticated call. I think it would make sense to ensure that is clearly exposed and then leave it up to the author to convert any other values from strings to whatever type they are attempting to pass through. Otherwise, we would need an extension to decode [String: Any] but with this method casting would be needed for every type including strings so the value in doing this is limited.

I think something like this would make the most sense:

            public let authorizer: Authorizer?

            public struct Authorizer: Codable {
                public let principalId: String
                public let context: [String: String]
                
                public init(from decoder: Decoder) throws {
                    let container = try decoder.container(keyedBy: CodingKeys.self)
                    self.principalId = try container.decode(String.self, forKey: .principalId)
                    self.context = try decoder.singleValueContainer().decode(Dictionary<String, String>.self)
                }
            }

If this sounds good I can throw up a PR with this implemented.

rmickeyd avatar Aug 07 '20 18:08 rmickeyd

sounds fine to me if it works correctly. @fabianfett opinion?

tomerd avatar Aug 08 '20 21:08 tomerd

sounds fine to me if it works correctly. @fabianfett opinion?

+1 from my side. We'll definitely need unit tests for this.

@bmoffatt Is there any document that describes all Authorizer payloads? Can we assume that will always be a dictionary with just String values and at least the principalId key?

Go uses interface{} for the values... https://github.com/aws/aws-lambda-go/blob/eebb9958b0b4c19edcfdff58326d0bf40e8ddf6b/events/apigw.go#L43

The closest thing that we have is AnyCodable, but I guess we don't want to add another dependency?

C# uses a [String: String] dictionary: https://github.com/aws/aws-lambda-dotnet/blob/e2bb81a4b48a402570b0de828772067938ca5671/Libraries/src/Amazon.Lambda.APIGatewayEvents/APIGatewayCustomAuthorizerContext.cs#L114

And thanks for reporting @rmickeyd. Because of the problems outlined above, I refrained from this feature so far. But we should definitely do something about it!

fabianfett avatar Aug 10 '20 07:08 fabianfett

Hi,
I have the same issue but I can't see the modified code or a PR with it. Any news on this? Was this implemented?

audente avatar Mar 08 '21 20:03 audente

I've added a PR with a [String:String] dictionary.

In my use case (Cognito -> API Gateway -> Lambda), I don't receive a 'principalID' key.

audente avatar Mar 08 '21 21:03 audente