Add Google authorization code sign in - #622
Merged
Merged
Conversation
There was a problem hiding this comment.
Important
A database concurrency conflict after redeeming a Google authorization code makes the new sign-in flow fail instead of retrying successfully.
Reviewed changes across the complete Google authorization code sign-in implementation and its tests:
- Auth routes and contracts: Added direct and operations-mirror endpoints with rate limits, request validation, OpenAPI schemas, and agent catalog entries.
- Google exchange and identity: Added an exact redirect allowlist, token exchange via the installed Google SDK, signed ID token validation, and production redirect configuration.
- Shared sign-in flow: Reused account provisioning, Google token storage, session creation, analytics, referral handling, and welcome email across both Google entry points.
- Tests: Added handler, validator, domain, controller, rate-limit, exchange, and claim-check coverage.
GPT Sol | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes since the prior Pullfrog review at 7147e975:
- Separated code exchange from retries: Redeemed and validated the Google authorization code once, then dispatched the validated identity to a retryable sign-in command for local persistence.
- Added concurrency regression coverage: Exercised the real MediatR retry behavior and verified that a database conflict retries the save without exchanging the code again.
GPT Sol | 𝕏
|
thomasluizon
added a commit
that referenced
this pull request
Sep 28, 2026
) * Add Render Terraform for production and staging (#621) * Add Terraform for Render production and staging * Handle Render database URLs without explicit ports * Keep production intact through the first apply and isolate staging integrations The imported API service ignores its own env_vars so the first apply only adds and links the environment group, and the existing Render project is imported (environments keyed by their live names) so the API stays in its Production environment while a Staging environment is added. Staging gets placeholder Stripe identifiers, staging return URLs, its own redirect allowlist and an invalid Supabase host, so it cannot touch production billing or storage. Empty custom domain lists become null, the landing no longer auto-deploys, and the web health check uses /api/health. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 1480d1b) * Store confirmed waitlist contacts in Orbit database (#620) * feat: store confirmed waitlist marketing contacts locally * fix: preserve marketing opt-outs and canonicalize waitlist languages * Restore user marketing delivery after explicit opt-in (cherry picked from commit 4c7b76a) * Add Google authorization code sign in (#622) * Implement Google authorization code sign in for ticket 796 * Register Google code routes in agent catalog * Parse Google token responses with installed SDK * fix: retry Google code sign-in after redemption (cherry picked from commit 2301ccc) * Add Cloudflare DNS and Turnstile to Terraform (#623) * Add Cloudflare DNS and Turnstile Terraform resources * Verify Cloudflare DNS answers before the registrar switch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 7e946a6) * Gate production API releases through Render (#624) * Add gated production API release workflow * Handle queued Render deploys and recheck the live commit before recording a release Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 78b42f2) * Keep Terraform from reverting web release digests (#627) * fix: preserve workflow deployed web digests in Terraform * docs: guard web service applies against Render image tag bug (cherry picked from commit b8ea2c1) * Configure staging billing from SSM and verify test purchases (#629) (cherry picked from commit 5e5623e) * Align Google code error assertion with redesign response --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Change
Adds
POST /api/auth/google/codeand its auth operations mirror for authorization codes with a verifier and an exact redirect URI allowlist. The new handler exchanges the code through a named Google HTTP client, validates the signed ID token, and returns the existing login response. Both Google entry points now useGoogleSignInFlowfor provisioning, reactivation, referral handling, welcome email, analytics, token storage, and session creation. The installed Google package parses the token response. The old Supabase route remains available for shipped clients.The route and request contract are in
src/Orbit.Api/Controllers/AuthController.csandsrc/Orbit.Api/openapi.json. The command, validator, shared flow, error codes, and Google exchange service are insrc/Orbit.Application,src/Orbit.Domain, andsrc/Orbit.Infrastructure. The auth capability and direct flow operation are registered in the agent catalog. Unit tests cover the exchange, claim checks, provisioning, token retention, reactivation, referral, route protection, and the catalog.Closes thomasluizon/orbit-tickets#796.
Assumptions
External interface evidence
src/Orbit.Infrastructure/obj/project.assets.jsonresolvesGoogle.Apis.Auth/1.76.0. The installed package at$HOME/.nuget/packages/google.apis.auth/1.76.0/lib/net6.0/Google.Apis.Auth.xmlexposesTokenResponse.FromHttpResponseAsync,IdToken,AccessToken, andRefreshToken, plusGoogleJsonWebSignature.ValidateAsync, audience and expiry validation settings, and the ID token email claims. The code lets the package parse Google's token response, so it does not read token response JSON fields itself. Reproduce the evidence withdotnet restore Orbit.slnxandrg 'TokenResponse.(IdToken|AccessToken|RefreshToken)|TokenResponse.FromHttpResponseAsync|ValidationSettings.Audience|Payload.EmailVerified' $HOME/.nuget/packages/google.apis.auth/1.76.0/lib/net6.0/Google.Apis.Auth.xml. The focused service test invokes the installed response parser and records its successful result.Manual steps
Google__AllowedRedirectUris__0and consecutiveGoogle__AllowedRedirectUris__Nentries to each exact callback URI before merging this PR. A successful production startup proves the list is present. A refused URI should returnGOOGLE_REDIRECT_URI_NOT_ALLOWEDwithout a Google request.Google__ClientIdandGoogle__ClientSecrethold the configured Google OAuth client credentials. A successful code exchange with that client proves they work.Google__ClientId. Add the same exact callback URIs under Authorized redirect URIs. A client authorization and code exchange using one of those URIs proves the setting took effect.0be4ffe8and its checks pass.Google__AllowedRedirectUris__0and subsequent numbered keys in the production API service’s Render > Environment screen. Confirm an allowed redirect succeeds and an unlisted redirect is rejected.Test evidence
env -u LANG LC_ALL=en_US.UTF-8 dotnet build Orbit.slnx -v:q: zero errors.env -u LANG LC_ALL=en_US.UTF-8 dotnet test --no-restore -v:q: 6,789 passed, zero failed.AgentCatalogServiceTests.EveryControllerAction_IsMappedToTheCatalogfirst failed on both new auth actions. It passed after their catalog entries were added.node tools/arch-map.mjs, the dash check, and the timeless check passed. The architecture map is generated locally and ignored by the repository.env -u LANG LC_ALL=en_US.UTF-8 dotnet build Orbit.slnx: passed, 0 errors.env -u LANG LC_ALL=en_US.UTF-8 dotnet test --no-restore: passed, 6,790/6,790 tests.