0

I have an Amplify app using Cognito for userpool authentication. Once a user has signed up and used the code sent via email (all Cognito functionality), they are passed to a custom form where additional information is captured. On submit a lambda function is executed that should:

  1. Create a group in Cognito
  2. Add the user to the group
  3. Create a record in a DynamoDB table and use the group name created in step 1. in a "writeGroups" fields referenced in the schema for allow.groupsDefinedIn('writeGroups')

The lambda function deploys nicely as part of my sandbox, and permissions have been granted for allow.resource(createAccount).to(["manageGroups", "addUserToGroup", "manageGroupMembership"])} as well as modifying DynamoDB data. However as soon as either CognitoIdentityProviderClient or await client.models.User.create(user) are hit from inside the lambda function, I get the following error from Graphql API No federated jwt. Example of code used:

const user = {
  userId: userId,
  ...
};
const { data, errors} = await client.models.User.create(user);   <-- `No federated jwt` error thrown here

Or

const cognitoClient = new CognitoIdentityProviderClient();
const userGroup = {
  GroupName: `GroupName`,
  Precedence: 1,
  Description: `Description`,
  UserPoolId: userPoolId,
};
const createCommand = new CreateGroupCommand(userGroup);
const response = await cognitoClient.send(createCommand );    <-- `No federated jwt` error thrown here

The examples in the Amplify Gen 2 documentation don't cover this scenario. What am I missing?

3
  • Where is the error occurring? inside Lambda or when calling the Lambda from frontend? Commented Jul 10 at 6:48
  • The error occurs in the lambda. Should I be using a different approach for interacting with Cognito and DynamoDB from within a lambda function perhaps?
    – Jonny
    Commented Jul 10 at 8:26
  • I resolved the Cognito issue by using the following client: let cognito = new AWS.CognitoIdentityServiceProvider(); ...then await cognito.createGroup(readGroup, function(err, data) {..... I just need to resolve how to hit DynamoDB with IAM credentials via this Amplify generated function and I'll provide an answer for this question clarifying the incorrect approach I initially took
    – Jonny
    Commented Jul 10 at 13:07

1 Answer 1

1

If the User data model is set to only allow owner, or authenticated users to create then you need to set the authMode for your client.models.user.create command to identityPool and pass in the user's jwtToken. The token can be retrieved from the header if you're using APIGateway to call the lambda. If you're not using API gateway you'll have to pass it in yourself.

Here's an example data

const schema = a.schema({
  User: a
    .model({
      name: a.string(),
      group: a.string(),
    })
    .identifier(["User"]),
})
.authorization((allow) => [allow.owner()]);

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "identityPool",
  },
});

And here's an example lambda called using APIGateway

export const handler: APIGatewayProxyHandler = async (event) => {

    let jwtToken: string | undefined;

    // Method 1: From JWT authorizer claims
    jwtToken = event.requestContext.authorizer?.jwt?.claims?.['id_token'] as string;

    // Method 2: From Authorization header (if token is passed in header)
    if (!jwtToken) {
        const authHeader = event.headers['Authorization'];
        jwtToken = authHeader;
    }
    if (jwtToken) {
        console.log('jwtToken found:', jwtToken);
        // Use the jwtToken as needed
    } else {
        console.log('jwtToken not found in the request');
    }

      const client = generateClient<Schema>({
        authMode: "identityPool",
        authToken: jwtToken,

      });
      const createStoryResult = await client.models.User.create({
        name: "foo",
        group: "Bar",
        },
      {
        authMode: "identityPool",
        authToken: jwtToken,
      });
1
  • 1
    Thanks Andrew, adding the JWT token did the trick. For me it was located in a slightly different location under event.request.headers['authorization']
    – Jonny
    Commented Jul 11 at 20:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.