javascripttypescriptsupabase

How can I implement and test an Auth Hook locally with SMS?


I'm using the docker project to run Supabase locally. I've already made a .override file and successfully integrated Google login with it.

I'm not quite sure how to configure the webhook, AWS SNS and how to test it locally.

services:
  auth:
    environment:
      GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${ENABLE_GOOGLE_SIGNUP}
      GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
      GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_CLIENT_SECRET}
      GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: http://localhost:8000/auth/v1/callback
      # more config things in here?

I'd like to configure a HTTP webhook like localhost:3000/api/test, not sure how to proceed with the Docker file. Are there any examples or does anyone know how to do this?


Solution

  • Create a docker-compose.override.yml, add

    services:
      auth:
        environment:
          GOTRUE_HOOK_SEND_SMS_ENABLED: ${HOOK_SEND_SMS_ENABLED}
          GOTRUE_HOOK_SEND_SMS_URI: ${HOOK_SEND_SMS_URI}
          GOTRUE_HOOK_SEND_SMS_SECRETS: ${HOOK_SEND_SMS_SECRETS}
    

    Update .env

    HOOK_SEND_SMS_ENABLED=true
    HOOK_SEND_SMS_URI=https://webhook.site/wwwwwwww
    HOOK_SEND_SMS_SECRETS=v1,whsec_wwwwwwwwwww
    

    Locally you can try localhost:#### or host.docker.internal:####

    Make sure to recreate the container docker-compose up.

    To validate the signature on the webhook, install standardwebhooks, you have to replace the useless v1,whsec_ part of your secret.

    import { Webhook } from "standardwebhooks";
    
    export const POST = async (req: NextRequest) => {
      const headers = Object.fromEntries(req.headers);
      const body = await req.text(); // important to be .text and not .json
    
      const wh = new Webhook(env.HOOK_SEND_SMS_SECRETS?.replace(/^v\d+,whsec_/, "") ?? "");
    
      let sms = { otp: "" };
      let user = {} as UserSmsResponse["user"];
    
      try {
        ({ sms, user } = wh.verify(body, headers) as {
          sms: UserSmsResponse["sms"];
          user: UserSmsResponse["user"];
        });
      } catch (err) {
        throw err;
      }
    
      // your custom sms sender stuff in here
    }
    

    Response type:

    interface UserSmsResponse {
      user: {
        id: string;
        aud: string;
        role: string;
        email: string;
        phone: string;
        phone_confirmed_at: string;
        confirmed_at: string;
        last_sign_in_at: string;
        app_metadata: {
          provider: string;
          providers: string[];
        };
        user_metadata: {
          email_verified: boolean;
          phone_verified: boolean;
          sub: string;
        };
        identities: Array<{
          identity_id: string;
          id: string;
          user_id: string;
          identity_data: {
            email_verified: boolean;
            phone_verified: boolean;
            sub: string;
          };
          provider: string;
          last_sign_in_at: string;
          created_at: string;
          updated_at: string;
        }>;
        created_at: string;
        updated_at: string;
        is_anonymous: boolean;
      };
      sms: {
        otp: string;
      };
    }