Does anyone have a good resource for adding role b...
# help
r
Does anyone have a good resource for adding role based access to api endpoints?
f
What you are trying to add?
r
I was thinking of using Cognito groups to allow an authenticated user access to an endpoint
I guess I am looking for a way to implement ACLs for an api
f
How are you protecting your api currently? IAM or JWT?
r
IAM
f
Got it, and you are trying to use the Cognito User Pool groups?
r
Yeah, I thought that might be the most straight forward way, I’m open to suggestions though.
f
Ah I see. I haven’t used User Pool groups. I’m managing that as part of my business logic. ie. I have a users table in DynamoDB and each user is assigned one or more roles. And I check the permission manually.
m
you add an attribute to user as "role" to the user pool shcema and then check the token in the business logic right??
f
Last time I checked, a year or two back, I wasn’t able to get the authenticated user’s user pool id/sub. That wasn’t passed in to the Lambda.
r
I was trying to avoid building that into the business logic, since Cognito supports groups, I thought that would be the go to, but I can’t seem to find any docs on making that work at all.
I was looking at Auth0 and they manage this by settings scopes in the JWT, is this something you can do with Cognito?
f
Yeah, so there are two ways you can authorize your Api endpoint, AWS or JWT.
r
How does the JWT option work?
f
If you go with JWT, you can use either Cognito or Auth0 to setup the scopes.
r
I’d like to stick with Cognito if possible.
f
Yeah, u can use Cognito with JWT
r
Is there an example anywhere?
We are going to publish more tutorial posts around JWT vs AWS
over the week
r
That would be awesome, happy to help test.
An how would the scopes be managed in cognito?
The internet seems to suggest that cognito groups get added to the claims like this:
Copy code
"cognito:groups": "[Group2 Group1]",
So I should be able to do some logic around that
f
I’m not too familiar with user User Pool, if you print out the lambda event object, you can see what scopes/claims are getting passed in
Copy code
export async function main(event) {
  console.log(event.requestContext.authorizer);
  return {
    statusCode: 200,
    body: `Hello ${event.requestContext.authorizer.jwt.claims.sub}!`,
  };
}
r
So if you use JWT auth, would that mean attachPermissionsForAuthUsers is no longer required?
You could give the lambda the required permissions instead and run it as long as the user has the required scope?
f
yeah, JWT ONLY authorizes the API, where as with IAM you can allow authorized users access any AWS resources via
attachPermissionsForAuthUsers
r
Copy code
An error occurred (InvalidParameterException) when calling the InitiateAuth operation: USER_PASSWORD_AUTH flow not enabled for this client
How do I enable this in auth?
f
How are you creating the user pool?
r
Copy code
// Create auth provider
    const auth = new sst.Auth(this, "Auth", {
      cognito: {
        signInAliases: { email: true },
      },
    });
f
Try this:
Copy code
import * as cdk from "@aws-cdk/core";
import * as cognito from "@aws-cdk/aws-cognito";
import * as apigAuthorizers from "@aws-cdk/aws-apigatewayv2-authorizers";
import * as sst from "@serverless-stack/resources";

export default class MyStack extends sst.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // Create User Pool
    const userPool = new cognito.UserPool(this, "UserPool", {
      selfSignUpEnabled: true,
      signInAliases: { email: true },
      signInCaseSensitive: false,
    });

    // Create User Pool Client
    const userPoolClient = new cognito.UserPoolClient(this, "UserPoolClient", {
      userPool,
      authFlows: { userPassword: true },
    });

    // Create Api
    const api = new sst.Api(this, "Api", {
      defaultAuthorizer: new apigAuthorizers.HttpUserPoolAuthorizer({
        userPool,
        userPoolClient,
      }),
      defaultAuthorizationType: sst.ApiAuthorizationType.NONE,
      routes: {
        "GET /private": "src/private.main",
        "GET /public": {
          function: "src/public.main",
        },
      },
    });

    // Show API endpoint in output
    new cdk.CfnOutput(this, "ApiEndpoint", {
      value: api.httpApi.apiEndpoint,
    });
    new cdk.CfnOutput(this, "UserPoolId", {
      value: userPool.userPoolId,
    });
    new cdk.CfnOutput(this, "UserPoolClientId", {
      value: userPoolClient.userPoolClientId,
    });
  }
}
sst.Auth
is currently designed for using the IAM, so it creates both a User Pool and an Identity Pool
r
Sure
f
Use the native CDK way to create a User Pool for now
and this line enabled the auth flow
authFlows: { userPassword: true },
r
Thank you, I will try this tomorrow and come back to you.