Skip to content

Conversation

@manueltorres0
Copy link
Contributor

@manueltorres0 manueltorres0 commented Jan 24, 2026

Description

  • Added clerk middleware that verifies JWT tokens to check that all incoming requests (except for clerk webhooks) are from an authenticated user
  • Added POST endpoint for the clerk webhook to create users when they sign up on clerk
  • Added a REQUIRED clerk id field to the user model because all user registration should come from clerk
  • Added test for both the middleware and the endpoint in the new tests folder
  • updated .env with clerk keys
  • added ngrok service on make run command to make the backend visible to clerk
  • provisionally changed the user POST endpoint to require the Clerk ID, this is until we figure out the sync endpoint

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • [] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (code improvement without changing functionality)
  • Documentation update
  • Configuration/infrastructure change
  • Performance improvement
  • Test coverage improvement

Related Issue(s)

Backend part of #71

What Changed?

  • middleware for verifying clerk-provided JWT tokens
  • endpoint to support clerk webhook triggered on created user
  • Added clerk id required field to user model

Testing & Validation

How this was tested

  1. Mocking the verification function for middleware, checking that it adds relevant information to context or rejects unauthorized reqs
  2. Mocking verification function for webhook endpoint, verifying that it checks the req for validity and passes the correct params

Unfinished Work & Known Issues

  • Missing good environment key selection, need the prod url and start a prod instance on clerk

  • None, this PR is complete and production-ready

  • The following items are intentionally deferred:

    • *** Sync endpoint creation / possible refactoring of current USER post (waiting on lead response)

Notes & Nuances

  • *** clerk id is required in the user model because it is the app's only valid way of creating a user

Pre-Merge Checklist

Code Quality

  • Code follows the project's style guidelines and conventions
  • Self-review completed (I've reviewed my own code for obvious issues)
  • No debugging code, console logs, or commented-out code left behind
  • No merge conflicts with the base branch
  • Meaningful commit messages that explain the "why"

Testing & CI

  • All CI checks are passing
  • All new and existing tests pass locally
  • Test coverage hasn't decreased (or decrease is justified)
  • Linting passes without errors

Documentation

  • Code is self-documenting or includes helpful comments for complex logic
  • API documentation updated (if backend endpoints changed)
  • Type definitions are accurate and up-to-date

Reviewer Notes

I did not add API docs to the webhook endpoint because this should never be called by our frontends

  • Areas needing extra attention: ...
  • Questions for reviewers: ...

Copy link
Contributor

@Dao-Ho Dao-Ho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an awesome first rip! 🔥 🔥 I left some comments for improvements. Also, for feats like these, it's very important to document your updates to the dev environment (include them in the pr body) and also attach a visual clip of the full flow working.

DOCKER_IMAGE_NAME := selfserve-backend
PORT := 8080
ENV_FILE := config/.env
NGROK_DOMAIN := undetestably-unidentical-selah.ngrok-free.dev
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ngrok domain is exclusively yours, we don't want this hardcoded. It also shouldn't be public, let's move it to be pulled from .env

I'd also look into regenerating your domain since you generally don't want your free plan's domain public like this

go build -o bin/$(APP_NAME) $(CMD_PATH)

run: db-start
@ngrok http --url=$(NGROK_DOMAIN) $(PORT) & \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't call the tunnel in the make run script. A couple reasons here:

  1. It's not always needed, adding extra overhead unnecessarily
  2. More layers of errors that the script needs to handle, the caller should determine if they need to tunnel something
  3. other services may be calling this script. Make run should just be doing exactly what it states to be doing- running our services/server, not forwarding our port in addition (this is a devs only step). Ex. Consider our CI pipeline trying to call make run


func setupClerk() {
if os.Getenv("ENV") == "development" {
clerksdk.SetKey(os.Getenv("DEV_CLERK_SECRET_KEY"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new vars added to .env should also be added to .env.sample

Also if you're adding new things like secrets, I'd make sure to add that to the PR body, it's an important change that affects the dev environment.

usersHandler := handler.NewUsersHandler(usersRepo)
reqsHandler := handler.NewRequestsHandler(repository.NewRequestsRepo(repo.DB))
hotelsHandler := handler.NewHotelsHandler(repository.NewHotelsRepo(repo.DB))
whVerifier, err := handler.NewWebhookVerifier()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whVerifier is really vague. Something I like doing is trying to use your variables that you name in a sentence and see if it makes sense. Let's rename this to be more explicit.

hotelsHandler := handler.NewHotelsHandler(repository.NewHotelsRepo(repo.DB))
whVerifier, err := handler.NewWebhookVerifier()
if err != nil {
fmt.Print(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why fmt.Print here? Let's throw the appropriate error

return svix.NewWebhook(os.Getenv("DEV_CLERK_WEBHOOK_SIGNATURE"))
}

func NewClerkHandler(userRepo storage.UsersRepository, WebhookVerifier WebhookVerifier) *ClerkHandler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your naming convention has been ClerkWebHook_. Let's maintain that here as well for consistency. NewClerkWebHookHandler

}

return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

making this a util was :chef-kiss: 🐐

err := r.db.QueryRow(ctx, `
INSERT INTO public.users (
first_name, last_name, employee_id, profile_picture, role, department, timezone
) VALUES (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing clerk_id in your insert statement. Was the insert working without?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants