Skip to content

feat: authenticate onboarding with a verified Google token#113

Open
jaspermayone wants to merge 4 commits into
mainfrom
jaspermayone/onboard-google-token-auth
Open

feat: authenticate onboarding with a verified Google token#113
jaspermayone wants to merge 4 commits into
mainfrom
jaspermayone/onboard-google-token-auth

Conversation

@jaspermayone

Copy link
Copy Markdown
Member

Matches WITCodingClub/calendar-backend#493. Merge together — the backend now rejects the old email-based onboarding.

What changed

  • loading/+page.svelte signIn() now fetches a Google OAuth access token via chrome.identity.getAuthToken and POSTs { google_access_token, preferred_name } to /user/onboard (instead of { email, preferred_name }). The backend verifies the token with Google and derives the email server-side, so a client can no longer mint a session for an arbitrary account.
  • Added a 401 retry that clears the cached Google token and re-onboards (handles token expiry — no separate refresh flow needed), and a 403 not_wit_account error state for non-@wit.edu Google accounts.
  • manifest.json: added the oauth2 block (getAuthToken requires it) and pinned the extension key.

Why the pinned key

getAuthToken only works when the OAuth client is registered against a specific extension ID, and unpacked dev builds otherwise get unstable per-machine IDs. The key pins dev builds to the stable production ID aceelinogfcceklkpacakdeddnaakicj (the value is the published extension's own public key, verified to hash to that ID), so a single OAuth client + single trusted backend client_id covers both dev and prod.

🔧 Required setup before merge

  1. In Google Cloud Console, create an OAuth client of type Chrome Extension (Application ID = aceelinogfcceklkpacakdeddnaakicj), scopes email profile.
  2. Put that client's ID into manifest.jsonoauth2.client_id (currently a placeholder).
  3. Add the same client ID to the backend GOOGLE_OAUTH_CLIENT_IDS env (comma-separated). Because dev now shares the prod ID, one entry covers both.

Notes

  • svelte-check passes on the changed file (the 19 pre-existing errors are all in calendar/+page.svelte, untouched here).
  • File left in its existing indentation style; prettier isn't enforced on it (base file already produces a full-file diff).

Send a chrome.identity Google access token to /user/onboard instead of a raw email/name. The backend verifies the token with Google and derives the account email, closing the account-takeover hole where any email could mint a session. Adds the oauth2 manifest block, a 401 re-onboard retry, and a 403 (non-@wit.edu) error state.
@jaspermayone jaspermayone requested a review from Cattn as a code owner July 1, 2026 20:23
@Cattn

Cattn commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
image

Also, this prevents people from choosing their personal email now? Is there a reason we have to change this

@jaspermayone

Copy link
Copy Markdown
Member Author

I fixed the id thing, I can add personal emails back, I lowkey forgot about that

Identity is the user's own (personal) Google account, verified server-side and used for both sign-in and calendar sync. Removes the @wit.edu-only restriction and its error state.
@jaspermayone

Copy link
Copy Markdown
Member Author

Good catches — both addressed:

The placeholder in your screenshot is now the real prod OAuth client ID (542377189189-…), so oauth2.client_id is filled in.

On personal emails — you're right, and I reworked it so it doesn't force a WIT account. Quick context on why the endpoint had to change at all: the old /user/onboard accepted a raw email and minted a permanent JWT for whatever account matched it — so anyone could POST someone@wit.edu and get a working token for that person's account (full takeover). It had to start verifying identity server-side.

The first pass I pushed verified a Google token but wrongly restricted it to @wit.edu. That's fixed now:

  • Onboarding uses the user's own (personal) Google account — the same one they sync their calendar to. No domain restriction.
  • The backend verifies the token with Google and keys the account to that verified email, so a caller can only ever reach the account tied to a Google identity they actually control — which is what closes the takeover hole, without forcing a WIT account.
  • Returning users are auto-linked to their existing account via a Google account they've already connected for calendar sync. (I intentionally don't link by the scraped WIT email — that value isn't verified, so trusting it would reopen the exact takeover.)

Net effect for users: one Google sign-in (their personal account) that covers both identity and calendar sync, instead of the old unverified email flow. Latest commits on this branch + WITCodingClub/calendar-backend#493 reflect this.

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