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)