Skip to content

Custom auth using Lambda function

0

I am trying to implement a custom Lambda function in my app in order to check users and federate data. The goal is to be able to federate data based on user using my current user management system. I have created my Lambda function and deployed it. My AppSync setup includes Lambda function as auth method (it is setup as secondary method).

When I test my Lambda function using a valid token, it returns "Authorized", which is expected. Also, when trying to create an elemento from AppSync query dashboard triggering a CreateItem function and specifying a valid token, it works and allows me to create an element. All these steps are logged on CloudWatch.

However, when I try to create an element from my frontend it seems that there's something wrong. It always return "Unauthorized" and I am not able to see logs on CloudWatch from the Lambda function. The data I'm using is similar on the test query and on my frontend, however there should be something wrong on the setup.

I'm a bit blocked on this step, since I don't know what could be wrong at all on my project setup.

This is my Lambda function:

const jwt = require("jsonwebtoken");
const crypto = require("crypto");

const jwkToPem = (jwk) => {
  const keyObject = crypto.createPublicKey({
    key: jwk,
    format: "jwk",
  });

  const pem = keyObject.export({
    type: "spki",
    format: "pem",
  });

  return pem;
};

exports.handler = async (event) => {
  // Log the incoming event to see the full request
  console.log("Received event:", JSON.stringify(event, null, 2));

  // Extract the authorization token from the headers (if available) or from the event directly
  const token =
    event.headers?.Authorization?.split(" ")[1] || event.authorizationToken;

  if (!token) {
    console.log("No token provided.");
    return {
      isAuthorized: false,
    };
  }

  console.log("Token received:", token);

  const secret = process.env.CLERK_API_KEY; 

  const fetch = await import("node-fetch").then((module) => module.default);

  // Fetch JWK from Clerk
  const res = await fetch("https://api.clerk.com/v1/jwks", {
    headers: {
      Authorization: `Bearer ${secret}`,
    },
  });

  if (!res.ok) {
    console.log("Failed to fetch JWK:", res.statusText);
    return { isAuthorized: false };
  }

  const data = await res.json();
  console.log("JWK fetched:", JSON.stringify(data, null, 2));

  const pem = jwkToPem(data.keys[0]);
  console.log("PEM generated:", pem);

  let decoded;
  try {
    decoded = jwt.verify(token, pem);
    console.log(
      "Token decoded successfully:",
      JSON.stringify(decoded, null, 2)
    );
  } catch (e) {
    console.log("Token verification failed:", e);
    return { isAuthorized: false };
  }

  console.log("User is authorized:", decoded.sub);

  return {
    isAuthorized: true,
    resolverContext: { owner: decoded.sub },
  };
};

Also, this is the handler I use in order to create an element:

export const handleAddProvider = async (provider, token) => {
  try {
    console.log("Token:", token);
    const response = await API.graphql({
      query: createProvider,
      variables: { input: provider },
      headers: {
        Authorization: `Bearer ${token}`, 
      },
    });
    console.log("Provider added:", response);
    return response;
  } catch (error) {
    console.error("Error adding provider:", error);
    throw error;
  }
};
1 Answer
0

Debugging Steps

Check for Differences in Token Handling:

Ensure that the token received in your frontend is identical to the one you're testing with in the AppSync query dashboard. Log the token in your frontend before sending it to verify its format.

Verify Headers on Frontend Request:

Ensure that the Authorization header is being correctly set in the request from the frontend.

Some frontends might add or modify headers automatically, so it’s important to verify this step.

CORS and Network Issues:

If the frontend is on a different domain than AppSync, ensure that CORS (Cross-Origin Resource Sharing) is properly configured.

Check browser developer tools for any network or CORS errors that might be preventing the request from going through correctly.

Check for Differences in Event Structure:

Log the event structure received in your Lambda function when triggered by the frontend versus the AppSync query dashboard. There might be differences in how the event is structured, especially in how headers or authorization tokens are passed.

Environment Variables:

Ensure that the CLERK_API_KEY environment variable is correctly set in the Lambda function environment.

Error Handling and Logs:

Double-check that all errors and unexpected paths are logged in your Lambda function to CloudWatch. You mentioned that you're not seeing logs from the frontend request, so consider adding a log statement at the very beginning of your Lambda handler to confirm if it’s being triggered.

Testing with Postman or Curl:

Try replicating the request from the frontend using a tool like Postman or Curl. This can help isolate whether the issue is in the frontend code or the AppSync configuration.

EXPERT
answered a year ago
EXPERT
reviewed a year ago
  • Thank you so much for your reply!

    I have tried several approaches. Since I cannot see at all the logs from the request from my frontend, I'm not sure if the token is correct. However, I am almost sure it is, since I have tested the same value from AWS console and worked.

    About the headers I use on this call, I can see on network tab that I am using the correct API-Key and the url to make the request is also correct. Not sure what else to check about the headers.

    About CORS and Network Issues, I don't see any error on logs or network tabs. The CLERK_API_KEY is also correct. Also, the Event Structure is the same and correct.

    Making the request using Curl I can see this error: "errors" : [ { "errorType" : "UnauthorizedException", "message" : "You are not authorized to make this call." } ]

    About the logs on my frontend request, I am not sure, but could be there request is not being sent through Lambda service? I am not even able to see the invocation of the request on CloudWatch.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.