Setup Google OAuth - SekiroKenjii/Quizzivy GitHub Wiki
Blocks the Phase 1 Google path (T-1.5 onward), which is every student's sign-in and the only self-signup route (ยง6.3). There is no workaround: the authorization-code exchange needs a real client secret, and E2E 3 mocks the GIS widget, not the exchange.
Owner: Thuong. Verify with make verify-google when done.
ยง2 named Google Identity Services; ยง5.3 required Authorization Code + PKCE. Those are incompatible, so we do not use the GIS SDK.
Google's authorization server supports PKCE โ its discovery document advertises
code_challenge_methods_supported: ["plain","S256"], and make verify-google
re-checks that every run. The GIS wrapper (initCodeClient) has no documented
way to pass a code_challenge. Thuong approved building the request directly.
So the flow is: generate a verifier, derive an S256 challenge, add state, open
Google's authorization_endpoint in a popup, and post
{ code, codeVerifier, redirectUri } to POST /auth/google. The client secret
never leaves the backend.
What this means for the console: the Authorized redirect URIs are the load-bearing setting. JavaScript origins are registered too, but nothing depends on them now.
https://console.cloud.google.com
Create one, or reuse an existing one. Name it quizzivy.
-
User type: External. Students are outside any Workspace org.
-
App name
Quizzivy, your support email, your developer contact email. -
Scopes:
openid,email,profileโ and nothing else.This matters. Those three are Google's non-sensitive scopes, and apps that request only non-sensitive scopes do not go through OAuth verification review. Adding anything else (Drive, Classroom, Calendar) puts the app into "sensitive" or "restricted" territory and triggers a review that can take weeks. ยง5.3 needs
sub,email,email_verified,name,pictureโ all covered by these three.
Set the app to "In production", not "Testing".
In Testing status, only users you add by hand to the test-user list can sign in at all. With ~50 students that means maintaining an allowlist, and every new student is blocked until you remember to add them โ a support burden that will land on you at the worst possible moment, in the middle of a test.
Because the app requests only non-sensitive scopes (step 2), publishing does not
require submitting for verification. The console tells you inline whether a
review is needed; if it offers to submit for verification, something other than
openid/email/profile crept into the scope list.
Unverified apps show an "unverified app" interstitial for sensitive scopes; with non-sensitive scopes only, students see the ordinary consent screen.
Credentials โ Create credentials โ OAuth client ID โ Web application.
Name it quizzivy-web.
Authorized JavaScript origins โ origins only, no path, no trailing slash:
http://localhost:5173
https://app.quizzivy.com
Authorized redirect URIs โ full URLs:
http://localhost:5173/auth/google/callback
https://app.quizzivy.com/auth/google/callback
The redirect URIs are what matter (see O-13 above). The JavaScript origins are registered anyway โ they cost nothing and keep the door open.
Replace app.quizzivy.com with the real host once O-01 is settled. Both must sit
under one registrable domain as the API โ that is what makes the SameSite=Lax
refresh cookie work (docs/plan/00-overview.md ยง4.1).
VITE_GOOGLE_CLIENT_ID=<the client id>.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-<the secret>
GOOGLE_REDIRECT_URI=http://localhost:5173/auth/google/callback
.env is gitignored and must stay that way. The client ID is public and ships
in the frontend bundle (ยง5.3); the secret is backend-only and must never
reach web/, a commit, or this chat.
make verify-googleThis needs no browser and no consent screen. It POSTs a deliberately invalid authorization code to Google's token endpoint using your real credentials. Google validates the client before the code, so the error it returns identifies the problem exactly:
| Google's response | Meaning |
|---|---|
invalid_grant |
Pass. The credentials are correct; only the dummy code was rejected. |
invalid_client |
The client ID or secret is wrong. |
redirect_uri_mismatch |
GOOGLE_REDIRECT_URI is not registered on this client. |
- Verify the ID token properly:
iss,aud,exp, and the signature via JWKS athttps://www.googleapis.com/oauth2/v3/certs. Cache the JWKS and refetch on an unknownkid. -
email_verified: falseis rejected outright โ no link, no create, even with a valid join code. This closes an account-takeover path and ยง5.1 states it without exception. - Google's
subis the stable identity; email can change.user_identitieskeys on(provider, provider_user_id)and storesemail_at_linkonly as a record of what it was.
Generated from docs/setup/google-oauth.md. Edit that file in the repository; changes made on this page are overwritten.