0

I got a nodeJS lambda function which returns database data and I'd like to filter that data based on the user. I created a custom authorizer lambda function which gets the user for a JWT token, but I couldn't find a way to pass data from the authorizer function to the database function, except for principalId (user.id).

What possibilities do I have here? Do I need to setup cognito? Or is there another possibility?

quambo
  • 470
  • 5
  • 11
  • Why is user id not enough? – arjabbar Jul 07 '16 at 21:26
  • Sorry for not being specific enough, but say the user is connected to an organization and I'd like to use the organization id for filtering in some cases, and the user id in other cases, so I'd need both available somehow. – quambo Jul 07 '16 at 21:38

3 Answers3

4

While reading documentation I found out something different from what the accepted answer suggests. Maybe it's new, but now output can include not only a principalId, but also a "context", which is an object. Sample:

{
    "principalId": "xxxxxxxx", // The principal user identification associated with the token send by the client.
    "policyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "execute-api:Invoke",
                "Effect": "Allow|Deny",
                "Resource": "arn:aws:execute-api:<regionId>:<accountId>:<appId>/<stage>/<httpVerb>/[<resource>/<httpVerb>/[...]]"
            }
        ]
    },
    "context": {
        "key": "value",
        "numKey": 1,
        "boolKey": true
    }
}

More from official documentation here. Much better aproach. :)

ᴛʜᴇᴘᴀᴛᴇʟ
  • 4,466
  • 5
  • 39
  • 73
bazaglia
  • 633
  • 1
  • 5
  • 20
1

It seems you have a couple of options.

1) You can place all the information about the user you need into the principal id that is set in the custom authorizer function. So maybe you could serialize the user as json or if you need just a couple of ids then concatenate them together with special character like: principalId: "userId|organizationId". I believe that there is some caching that API Gateway does around that principal id that is returned so I wouldn't make it anything that could be highly dynamic. You could also turn off caching for authorization as well, but that would slow down that endpoint as a result.

2) Just pass the user id and do the user lookup again to get all the information in the function that does the database call. If you're using DynamoDB it will be fast supposedly.

And Cognito seems nice but I don't think it will help you solve the particular problem that you're having now. If it was me though I would choose option 2.

arjabbar
  • 6,044
  • 4
  • 30
  • 46
  • Thanks, I will use a mix of both, structuring the token data / principalId (in my case) "org/userId". In the few cases I'll need more I'm going to load the user. – quambo Jul 08 '16 at 07:23
1

One possible way is to encode the data object to base64 string from authorizer lambda function and decode it down the line.

 var principalId = new Buffer(JSON.stringify({
   id: 5,
   name: "John"
 })).toString('base64');

 var policy = require('./policy.json');

 var policyConfig = {
   "principalId": principalId,
   "policyDocument": policy
 };

 context.succeed(policyConfig);

Decoding can be done in two places, one place is the request template section. This can be done by writing a transformation in velocity scripts as shown below

{
      "requestTemplate": {
        "application/json": {
          "principal": "$util.urlEncode($util.base64Decode($context.authorizer.principalId))"
        }
      }
 }

Other option is to decode inside the endpoint lambda function with the nodejs Base64 decoding. Check the following link for more information. stack overflow answer for base64 decode

Community
  • 1
  • 1
Ashan
  • 18,898
  • 4
  • 47
  • 67