Skip to content

Add Google authorization code sign in - #622

Merged
thomasluizon merged 4 commits into
mainfrom
fix/ticket-796-google-code-signin
Sep 27, 2026
Merged

thomasluizon merged 4 commits into
mainfrom
fix/ticket-796-google-code-signin

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Change

Adds POST /api/auth/google/code and 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 use GoogleSignInFlow for 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.cs and src/Orbit.Api/openapi.json. The command, validator, shared flow, error codes, and Google exchange service are in src/Orbit.Application, src/Orbit.Domain, and src/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

  • The operations mirror applies to anonymous auth flows because every existing anonymous auth route has one; omitted the alternative of treating authenticated account actions as part of that mirror requirement.
  • Auth errors in this repository carry stable codes and English server messages, with no backend locale resources; used that established pattern for the new codes instead of adding a new translation mechanism in the API. Client copy for both locales belongs to the blocked UI ticket.
  • Production needs its redirect URI list before the API deploy because this ticket requires startup validation; rejected setting it only when the UI deploys.
  • Kept the existing Google sign-in command’s retry behavior and moved only code sign-in’s persistence work into a retryable command. Changing the existing endpoint’s retry behavior was outside this review finding.

External interface evidence

src/Orbit.Infrastructure/obj/project.assets.json resolves Google.Apis.Auth/1.76.0. The installed package at $HOME/.nuget/packages/google.apis.auth/1.76.0/lib/net6.0/Google.Apis.Auth.xml exposes TokenResponse.FromHttpResponseAsync, IdToken, AccessToken, and RefreshToken, plus GoogleJsonWebSignature.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 with dotnet restore Orbit.slnx and rg '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

  • In Render, open the production Orbit API service Environment screen and set Google__AllowedRedirectUris__0 and consecutive Google__AllowedRedirectUris__N entries to each exact callback URI before merging this PR. A successful production startup proves the list is present. A refused URI should return GOOGLE_REDIRECT_URI_NOT_ALLOWED without a Google request.
  • In the same Render Environment screen, confirm Google__ClientId and Google__ClientSecret hold the configured Google OAuth client credentials. A successful code exchange with that client proves they work.
  • In Google Cloud Console, open APIs & Services, Credentials, then the OAuth 2.0 client identified by 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.
  • In GitHub PR Add Google authorization code sign in #622, the orchestrator must push this commit to the existing branch. Confirm the PR head is 0be4ffe8 and its checks pass.
  • Before clients use the code endpoint, set Google__AllowedRedirectUris__0 and subsequent numbered keys in the production API service’s Render > Environment screen. Confirm an allowed redirect succeeds and an unlisted redirect is rejected.
  • Add those same URIs in Google Cloud Console > APIs & Services > Credentials > OAuth 2.0 client > Authorized redirect URIs. Confirm a code issued for an allowed URI exchanges successfully.

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.
  • The existing AgentCatalogServiceTests.EveryControllerAction_IsMappedToTheCatalog first 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.
  • Existing Google code handler tests passed before the fix: 7/7.
  • New regression test failed before the fix: expected one exchange, observed two. It passed after the fix: 8/8 focused tests.
  • 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.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread src/Orbit.Application/Auth/Commands/GoogleCodeAuthCommand.cs Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ 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.

Pullfrog  | View workflow run | Using GPT Sol | 𝕏

@sonarqubecloud

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit 2301ccc into main Sep 27, 2026
25 checks passed
@thomasluizon
thomasluizon deleted the fix/ticket-796-google-code-signin branch September 27, 2026 22:37
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>
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.

1 participant