Skip to content
  • Integrations
  • Webhooks

Set up webhooks using NextJS

While webhooks will work with any NextJS setup, this guide uses NextJS 14 with app router and the app directory. You may need to alter some code samples if you have a different setup, but the core instructions remain the same.

Set up local development

Link to this section

In order to use webhooks, you need a publicly available URL. To test locally you need to use a proxy to expose your local instance on the internet. Here are a couple of free tools to help you to do this.

  • localtunnel - fast and easy, we recommend using the —subdomain attribute to fix the issued subdomain.
  • Ngrok - for intermediate users, requires some dev experience to get set up.

Each of these services expose a local port though a public URL that can be set as your web socket. Follow their instructions to run your local NextJS application and you will receive a URL that you need later in this guide.

Create the Kinde webhook route

Link to this section

Kinde sends webhooks as JWT’s to make them both easy and secure. In this example we will leverage 2 libraries to parse the JWT and verify the signature.

  1. Create the file app/api/kinde-webhook/route.ts. The route.ts file is a specific file convention in NextJS that marks the route as an API route, rather than a page.

    app/api/kinde-webhook/route.ts
    import { NextResponse } from "next/server";
    export async function POST(req: Request) {
    return NextResponse.json({ status: 200, statusText: "success" });
    }

    Whenever an event occurs in Kinde, a POST request is sent via this route to the specified endpoint, so that your project can react to the event. For example, refreshing a token or updating data in your database.

    Note that the endpoint needs to be publicly available, with no route protection.

  2. Install the dependencies.

    Terminal window
    #npm
    npm i jwks-rsa jsonwebtoken
    #yarn
    yarn add jwks-rsa jsonwebtoken
    #pnpm
    pnpm i jwks-rsa jsonwebtoken
  3. Update your file as follows:

    app/api/kinde-webhook/route.ts
    import { NextResponse } from "next/server";
    import jwksClient from "jwks-rsa";
    import jwt from "jsonwebtoken";
    // The Kinde issuer URL should already be in your `.env` file
    // from when you initially set up Kinde. This will fetch your
    // public JSON web keys file
    const client = jwksClient({
    jwksUri: `${process.env.KINDE_ISSUER_URL}/.well-known/jwks.json`,
    });
    export async function POST(req: Request) {
    try {
    // Get the token from the request
    const token = await req.text();
    // Decode the token
    const { header } = jwt.decode(token, { complete: true });
    const { kid } = header;
    // Verify the token
    const key = await client.getSigningKey(kid);
    const signingKey = key.getPublicKey();
    const event = await jwt.verify(token, signingKey);
    // Handle various events
    switch (event?.type) {
    case "user.updated":
    // handle user updated event
    // e.g update database with event.data
    console.log(event.data);
    break;
    case "user.created":
    // handle user created event
    // e.g add user to database with event.data
    console.log(event.data);
    break;
    default:
    // other events that we don't handle
    break;
    }
    } catch (err) {
    if (err instanceof Error) {
    console.error(err.message);
    return NextResponse.json({ message: err.message }, { status: 400 });
    }
    }
    return NextResponse.json({ status: 200, statusText: "success" });
    }

    As per the sample above, the JWKs file is fetched from Kinde, the token is decoded, and the signature is compared against your keys file. This is how you know you can trust the request has come from Kinde.

    💡 Handling different event types. In the example above, we used a switch statement. But you could also set up an endpoint per event type, group them into related endpoints, use a map, or any other method for splitting and managing the events.

  4. Start your server so it’s ready and listening out for the next step. With most NextJS applications, run npm run dev in the terminal.

Set up the webhook in Kinde

Link to this section
  1. In the Kinde, go to Settings > Environment > Webhooks.

  2. Select Add webhook.

  3. Give the webhook a name and description.

  4. Enter the NextJS endpoint we set up earlier in your project. For example <your_app_url>/api/kinde-webhook. If you are using an external tool to test the endpoint locally, enter the endpoint URL specified in the tool.

    ⚠️ Make sure URLs match. Testing will fail if the endpoint URL in Kinde does not match the site URL where you are testing the webhook.

  5. Select Add events.

  6. In the dialog that opens, select the events you want. For example, user events, organization events, etc.

  7. Select Save.

  8. In the webhook window, select Save.

Test the webhook

Link to this section
  1. Either create a new user or update an existing one in Kinde.
  2. Switch back to where your server is running and you should see the data in your server console.
  3. Done! Have a tasty beverage.