Skip to content

custom domains - auth sync #2180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 70 commits into
base: master
Choose a base branch
from

Conversation

Soxasora
Copy link
Member

@Soxasora Soxasora commented May 25, 2025

Description

Part of #1942
Focuses on synchronizing authentication between SN and a custom domain.
It features a new sync endpoint that checks if there's a session and if so, redirects to the custom domain with a verification token that gets exchanged with a session token via POST.

Media

Auth Sync Login

Screen.Recording.2025-05-25.at.21.39.07.mp4

Additional Context

The interested code is in /api/auth/sync.js and /middleware.js
Edits to /nav/common has been made to accommodate Next Auth

Flow:

  1. User, on custom domain, goes to /login or /signup
  2. Middleware redirects to /api/auth/sync on SN and checks if there's a session
    ---> yes: Issue a verification token
    ---> no: Redirect to /login or /signup on SN with callback /api/auth/sync so we can resume auth sync
  3. Redirect back to custom domain with the verification token
  4. Middleware checks if there's a token param and make a POST to /api/auth/sync to exchange this token with a session token
  5. Middleware applies the session token to a session cookie

Using a verification token and validating it with a POST is safer than the previous method of exposing a JWT directly

Future TODOs with priority:

  • a page asking user confirmation before proceeding - 3/10
  • pick an SN account to synchronize - 3/10
  • multi auth - 6/10

Checklist

Are your changes backwards compatible? Please answer below:
Yes, only engages on custom domains

On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:
6, Q/A OK, edge cases handled correctly

For frontend changes: Tested on mobile, light and dark mode? Please answer below:
n/a

Did you introduce any new environment variables? If so, call them out explicitly here:
n/a

Soxasora and others added 30 commits May 1, 2025 18:38
- ACM support
- custom domains crud, resolvers, fragments
- custom domains form, guidelines
- custom domains context
- domain verification every 5 minutes via pgboss
- domain validation schema
- basic custom domains middleware, to be completed
- TODOs tracings
- CustomDomain -> Domain
- DomainVerification table
- CNAME, TXT, SSL verification types
- WIP DomainVerification upsert
…ange status of a Record from its Attempt, multi-purpose dns verification
- use DomainVerificationStatus enum for domains and records
- adapt Territory Form UI to new schema
- return 'records' as an object with its types
- wip: prepare for attempts and certificate usage for prisma
fix:
- fix setDomain mutation transaction
- fix schema typedefs

enhance:
- DNS records guidelines with flex-wrap for longer records

cleanup:
- add comments to worker
- remove console.log on validation values
… HOLD

handle territory changes via triggers
- on territory stop, HOLD the domain
- on territory takeover from another user, delete the domain and its associated records

handle ACM certificates via trigger
- on domain/domainCertificate deletion, ask ACM to delete the certificate via a pgboss job; removes the need to ask ACM in multiple places

clear domains that have been on HOLD for more than 30 days, check every midnight via pgboss schedule

use 'domains' profile for worker jobs
Soxasora and others added 11 commits May 25, 2025 20:03
- cleanup and comments

Middleware:
- redirects to auth sync API endpoint
- supports signup redirects
- if it receives a verification token, sends a POST to auth sync API endpoint and exchange it for a JWT session token
- applies session token from the POST
- gets rid of next auth functions

GET Auth Sync:
- issue a verification token tied to the session token's user id
- support signup and redirect accordingly
- use getToken from Next-Auth to get the live session token
- also validate domain param through custom domain schema validation before checking if ACTIVE

POST Auth Sync:
- consume the verification token by checking its existence in DB and deleting it afterwards
- create and return ephemeral JWT session token
@Soxasora Soxasora force-pushed the custom_domains_authsync branch from 46a23cc to 171405b Compare May 29, 2025 21:53
@Soxasora Soxasora marked this pull request as ready for review June 2, 2025 15:02
@Soxasora Soxasora marked this pull request as draft June 6, 2025 19:25
- user's csrf cookie is sent as 'state' to the sync endpoint
- 'state' is preserved in the DB, coupling it with the verification token
--- verificationToken|csrfToken
- consuming a verification token via POST requires the csrfToken

- consuming a token also means deleting it from DB, a transaction is used to ensure this
@Soxasora Soxasora force-pushed the custom_domains_authsync branch from 17568c5 to 932f4e3 Compare June 10, 2025 09:15
@Soxasora Soxasora force-pushed the custom_domains_authsync branch from 3335d66 to f25b57a Compare June 10, 2025 23:23
…to compare it with the POST sent CSRF token, to get the final JWT session
@Soxasora Soxasora force-pushed the custom_domains_authsync branch from f25b57a to 1346057 Compare June 10, 2025 23:25
Comment on lines +126 to +127
// store encoded state JWT with the verification token to prevent CSRF attacks
token: `${randomBytes(32).toString('hex')}|${state}`,
Copy link
Member Author

@Soxasora Soxasora Jun 10, 2025

Choose a reason for hiding this comment

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

There were some obstacles because of the cross-domain nature, but I think I found a middle ground to safely use CSRF to tie the verification token to the user.
Knowing that:

  • messing with next auth is not preferable and thus can't use its protections
  • we need to protect the token from being stolen
  • middleware doesn't support node
    We have another option, which is to encode the CSRF token in a state JWE and store it alongside the verification token.

When going to the sync endpoint, we

  • detect login -> encode CSRF token in state JWE -> /api/auth/sync/?...&state=encodedState

The sync endpoint will then

  • create a token like token|encodedState -> redirect back with just the token

Middleware at this point will

  • POST /api/auth/sync with body: {token, csrfToken} -> retrieve the verification token object from DB -> decode the encodedState -> match decodedState with csrfToken

If everything is okay, it returns the final ephemeral JWT.

Everything happens blazingly fast, if someone steals the verification token and/or the state, they can’t go that far without the CSRF token that sits and never moves in the user’s browser (well, except for the POST, but that's secure).


side note: still checking for less hacky ways/can make it less hacky

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.

2 participants