Skip to content

Rebuild the MCP authorize page on the redesign - #665

Merged
thomasluizon merged 2 commits into
redesign/mainfrom
feature/ticket-946-mcp-oauth-page
Sep 29, 2026
Merged

thomasluizon merged 2 commits into
redesign/mainfrom
feature/ticket-946-mcp-oauth-page

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Closes #946.

The authorize page at /oauth/authorize was the last Orbit sign-in surface still on the pre-redesign look. It now draws against the granted Orbit Entrar and Orbit Verificacao drawings and the design system's own tokens.

What changed

The letter "O" in a violet gradient square is gone. The page draws the orbital mark from design/brand/orbit-mark-accent.svg, inlined, with the accent on its moon and --fg-1 everywhere else.

No gradient survives anywhere, on the mark tile or the primary button. Manrope from Google Fonts is gone: the three latin webfont subsets the app itself ships (Geist, Space Grotesk, Geist Mono, byte-identical to apps/web/fonts/) are embedded in the assembly and served from /oauth/assets/{name} behind a closed allowlist, with an immutable one-year cache. Their SIL OFL licences ship beside them.

Every colour, size, radius and space reads a token copied from design/canvas/_ds/.../tokens/ and DESIGN.md. The accent is the warm orange #C4530F, not the violet the page carried. Dark and light both ship and follow prefers-color-scheme. The green success banner is gone: success is a neutral role="status" line, since only overdue and bad carry a hue.

The field, the six-digit code input, the pill button and the ghost control mirror the shipped input.tsx, otp-input.tsx and pill-button.tsx geometry, so the two surfaces cannot drift. The six cells sit behind one real input, so backspace, autofill and pasting a whole code are the browser's. The drawn Google button carries the word and no logo, which is what the Entrar drawing specifies.

Every string renders in English and pt-BR, picked from Accept-Language. The wording reuses the Entrar drawing's own approved strings wherever they exist. The code email now goes out in the same language the page is rendered in, which it did not before.

The consent content stays: the eyebrow names the client, and the list says what the client may do.

The page's parameters and its words travel in two application/json blocks rather than generated source, so no request value reaches executable text. The serializer keeps accents readable and escapes what could end a script block early.

Test evidence

Both observations come from tests/Orbit.Infrastructure.Tests/Controllers/OAuthLoginPageTests.cs, which is new.
Unchanged test with the defect present. dotnet test tests/Orbit.Infrastructure.Tests/Orbit.Infrastructure.Tests.csproj --filter "FullyQualifiedName~OAuthControllerTests" on the old page: Failed: 0, Passed: 83. The old suite asserted the Google error path and the redirect wiring, and nothing about the look, so a violet gradient tile and a Google Fonts link passed it.
Strengthened test failing before the fix. The new file was written first and run against the old page, restored from HEAD, with the same command filtered to FullyQualifiedName~OAuthLoginPageTests: Failed: 12, Passed: 5, Total: 17. The twelve failures were the mark, the gradient and font host ban, the self-hosted faces, the token-only colour rule, the colour-scheme rule, the six cells, both sign-in paths, and both locale theories. The five that passed were the asset endpoint and the JSON escaping, which the old page did not reach.
After the fix. The same filter: Failed: 0, Passed: 17. The whole OAuth set, filtered to FullyQualifiedName~OAuth: Failed: 0, Passed: 119. dotnet test Orbit.slnx: Failed: 0, Passed: 8200 across the four projects.
Guards run locally: check-dashes.mjs --files on every changed file, check-timeless.mjs --base origin/redesign/main, check-suppression-allowlist.mjs, check-root-allowlist.mjs, all clean. node tools/arch-map.mjs regenerated both maps, which are not committed. src/Orbit.Api/openapi.json is tracked and regenerated by the build, so the new route's entry rides in the same commit.

  • Review fix 87129745 (orchestrator): the OAuth Content-Security-Policy in SecurityHeadersMiddleware now allows same-origin fonts, styles and scripts only (font-src 'self', style-src 'self' 'unsafe-inline', script-src 'self' 'unsafe-inline'), because the rebuilt page self-hosts its fonts under /oauth/assets and loads no Google script or stylesheet. InvokeAsync_OAuthPath_AllowsOnlySameOriginFontsStylesAndScripts replaces the old Google-host assertions.
  • With the middleware change stashed, dotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~SecurityHeadersMiddlewareTests failed 1 of 11; with it, the security header and OAuth filter passed 129 of 129.
  • Full dotnet test Orbit.slnx: exit 0, 8,200 passed (32 analyzers, 641 domain, 4,647 application, 2,880 infrastructure).

Assumptions

  • The mark is drawn standalone at 48px rather than inside the Entrar Lockup, because Lockup.d.ts mandates the monochrome mark while the ticket's later comment requires the accent file. Rejected alternative: the lockup with a tinted mark, which would contradict the design system contract and the rule that a surface never tints the monochrome file itself.
  • The fonts are served from a new /oauth/assets/{name} action with a closed allowlist, not from a wwwroot static file handler. Rejected alternative: UseStaticFiles(), which adds global middleware and a directory whose contents no allowlist bounds.
  • The code step's action is disabled until six digits are present, and the email action until an address is typed, following the drawings. Rejected alternative: an always enabled action plus an incomplete-code message, which the drawings do not show and which would leave that message unreachable.
  • The one alert region sits under the title rather than beside each control. The drawings put the send failure above the action and the Google failure under its button. Rejected alternative: two alert regions, which the single-error server contract does not feed.
  • The Entrar legal line is not carried over. It needs terms and privacy URLs that this repository does not hold, and inventing them is a product call.
  • The OAuth CSP drops the Google script and font hosts entirely, since nothing under /oauth loads from them after the redirect sign-in and this rebuild.

Manual steps

None.
🤖 Generated with Claude Code

  • None.

The authorize page at /oauth/authorize was the last Orbit sign-in surface on
the pre-redesign look: a letter tile in a violet gradient square, a gradient
primary button, Manrope from Google Fonts, hard-coded hexes, a green success
banner and English only.

It now draws against the granted Entrar and Verificacao drawings and the design
system's own tokens. The orbital mark carries the accent on its moon and nothing
else. The three latin webfont subsets ship inside the assembly and serve from
/oauth/assets/{name} behind a closed allowlist, so no third-party font host
appears on a sign-in surface. Dark and light both ship and follow
prefers-color-scheme. Every string renders in English and pt-BR, chosen from
Accept-Language, and the code email now goes out in the same language.

The page's parameters and its words travel in two JSON blocks rather than
generated source, so no request value reaches executable text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@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

The new self-hosted fonts are blocked by the OAuth page's Content Security Policy, so the redesigned typography will not load in browsers.

Reviewed changes The MCP authorize page rebuild, its asset endpoint, localization, and tests were reviewed.

  • Page and interaction: Replaces the old markup and inline behavior with token-based styling, a six-cell code input, and English and Brazilian Portuguese copy.
  • Asset delivery: Embeds three font files, serves them through an allowlisted OAuth route, and updates OpenAPI and capability coverage.
  • Safety and tests: Moves request data into escaped JSON blocks and adds page and controller assertions.

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

Comment thread src/Orbit.Api/OAuth/OAuthPageStyles.cs
The rebuilt MCP authorize page serves Geist and Space Grotesk from
/oauth/assets and loads no Google script or stylesheet, so the OAuth
Content-Security-Policy allows same-origin fonts, styles and scripts only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@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 I reviewed the follow-up OAuth Content Security Policy change and its middleware test against the full authorize page rebuild.

  • Font delivery: Allowed same-origin font assets under /oauth/assets while removing unused Google hosts from the OAuth policy.
  • Policy coverage: Updated the middleware test to assert the same-origin font, style, and script directives.

Pullfrog  | View workflow run | Using GPT Sol | 𝕏

@thomasluizon
thomasluizon merged commit f039e1a into redesign/main Sep 29, 2026
22 checks passed
@thomasluizon
thomasluizon deleted the feature/ticket-946-mcp-oauth-page branch September 29, 2026 18:51
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