The Whole Motive behind this blog is Auth is hard and a bit of pain to set up in AWS Cognito.With All Due AWS Cognito is a great service but has a learning curve.
So, lets learn how to integrate all this stack together
The common assumption you have a Nextjs Project clerk ready and a Users table in DynamoDB in your specific region
I have Users Table deployed with Partition key as ClerkID
So first let's get started with our nextjs Project
Folder Structure lib->actions->user.action.ts
"use server";
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall } from "@aws-sdk/util-dynamodb";
export const createUser = async ({
clerkId,
name,
username,
email,
picture,
}: {
clerkId: string;
name: string;
username: string;
email: string;
picture: string;
}) => {
const ddbClient = new DynamoDBClient({
region: process.env.AWS_REGION as string,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID as string,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
},
});
const params = {
TableName: "Users",
Item: marshall({
ClerkID: clerkId,
Name: name,
Username: username,
Email: email,
Picture: picture,
}),
};
try {
await ddbClient.send(new PutItemCommand(params));
} catch (err) {
throw err;
}
};
As you see this code runs on server so lets update our next config too
next.config.mjs
const nextConfig = {
experimental: {
mdxRs: true,
serverComponentsExternalPackages: [
"@aws-sdk/client-dynamodb",
"@aws-sdk/util-dynamodb",
],
}
}
Now the API Post route in your app directory
This all is explained in the Documentation for clerk
Now in our App Directory
app->api->webhook->route.ts
/* eslint-disable camelcase */
import { Webhook } from "svix";
import { headers } from "next/headers";
import { WebhookEvent } from "@clerk/nextjs/server";
import { createUser } from "@/lib/actions/user.action";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
// You can find this in the Clerk Dashboard -> Webhooks -> choose the webhook
//
const WEBHOOK_SECRET = process.env.NEXT_CLERK_WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) {
throw new Error(
"Please add WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local"
);
}
// Get the headers
const headerPayload = headers();
const svix_id = headerPayload.get("svix-id");
const svix_timestamp = headerPayload.get("svix-timestamp");
const svix_signature = headerPayload.get("svix-signature");
// If there are no headers, error out
if (!svix_id || !svix_timestamp || !svix_signature) {
return new Response("Error occured -- no svix headers", {
status: 400,
});
}
// Get the body
const payload = await req.json();
const body = JSON.stringify(payload);
// Create a new SVIX instance with your secret.
const wh = new Webhook(WEBHOOK_SECRET);
let evt: WebhookEvent;
// Verify the payload with the headers
try {
evt = wh.verify(body, {
"svix-id": svix_id,
"svix-timestamp": svix_timestamp,
"svix-signature": svix_signature,
}) as WebhookEvent;
} catch (err) {
console.error("Error verifying webhook:", err);
return new Response("Error occured", {
status: 400,
});
}
const eventType = evt.type;
console.log({ eventType });
// write this block by yourself
try {
// ... (existing code)
if (eventType === "user.created") {
const {
id,
email_addresses,
image_url,
username,
first_name,
last_name,
} = evt.data;
try {
console.log("Creating user...");
const user = await createUser({
clerkId: id,
name: `${first_name}${last_name ? ` ${last_name}` : ""}`,
username: username!,
email: email_addresses[0].email_address,
picture: image_url,
});
return NextResponse.json({ message: "OK", user: user });
} catch (err) {
console.error("Error creating user:", err);
return new Response("Error creating user", { status: 500 });
}
}
return new Response("", { status: 201 });
} catch (err) {
console.error("Error in API route:", err);
return new Response("Internal Server Error", { status: 500 });
}
}
Deploy your website to Vercel or any other provider add your webhook endpoint of the deployed website to the environment variables here are images to do so
eg : www.example.com/api/webhook
Make sure you add NEXT_CLERK_WEBHOOK_SECRET in your .env.local
Here what .env.local should look like when deployed
Taddaa you are all set
Top comments (0)