Skip to content

feat(planetscale): OAuth login + shared landing pages#467

Open
Mkassabov wants to merge 6 commits into
mainfrom
pear/oauth
Open

feat(planetscale): OAuth login + shared landing pages#467
Mkassabov wants to merge 6 commits into
mainfrom
pear/oauth

Conversation

@Mkassabov

@Mkassabov Mkassabov commented May 29, 2026

Copy link
Copy Markdown
Contributor

Adds browser-based OAuth login for PlanetScale, mirroring the Cloudflare flow, plus the shared OAuth landing pages on the website.

PlanetScale OAuth

alchemy login now offers OAuth alongside env vars and service tokens.

authorize → browser → localhost:9976/auth/callback → exchange → store → /auth/success
  • Planetscale/OAuthClient.ts — authorize/exchange/refresh/callback over a localhost loopback
  • Planetscale/AuthProvider.tsoauth method through configure/login/resolve (proactive refresh)/logout/prettyPrint
  • Planetscale/Credentials.ts — resolves OAuth creds to a Bearer token

PlanetScale differs from Cloudflare: no PKCE, so the app client_secret ships in the CLI (same exposure posture as a public client_id; rotate via release). Scopes are configured on the OAuth app, not requested per-authorization, and there's no revocation endpoint, so logout just drops local tokens.

Website landing pages

website/src/pages/auth/
├── success.astro    → /auth/success    credentials saved, return to the CLI
└── error.astro      → /auth/error      authorization failed

Provider-agnostic — the CLI loopback already knows which provider it started, so one shared pair covers Cloudflare, PlanetScale, and future providers.

Before merge (draft)

@alchemy-version-bot

alchemy-version-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Install the packages built from this commit:

alchemy

bun add alchemy@https://pkg.ing/alchemy/793a93b

@alchemy.run/better-auth

bun add @alchemy.run/better-auth@https://pkg.ing/@alchemy.run/better-auth/793a93b

@alchemy.run/pr-package

bun add @alchemy.run/pr-package@https://pkg.ing/@alchemy.run/pr-package/793a93b

@Mkassabov Mkassabov closed this May 29, 2026
@Mkassabov Mkassabov reopened this May 29, 2026
@Mkassabov Mkassabov changed the title feat(website): add OAuth landing pages feat(planetscale): OAuth login + shared landing pages May 29, 2026
@alchemy-version-bot

Copy link
Copy Markdown
Contributor

Website Preview Deployed

URL: https://alchemyeffectwebsite-worker-pr-467-r63v3jsdctsuvebd.testing-2b2.workers.dev

Built from commit 00f3b9c.


This comment updates automatically with each push.

Mkassabov added 5 commits June 5, 2026 16:43
Move the OAuth success/error landing pages from async-alchemy onto this
website, restyled with the design tokens and ThemeProvider.

The CLI runs a localhost loopback server as the OAuth redirect_uri; after
it exchanges the code for tokens it 302-redirects the browser to these
pages purely as "you can close this window" UI. They are provider-agnostic
(the loopback server already knows which provider it started for), so a
single shared success/error pair covers all providers.

- /auth/success   credentials saved, return to the CLI
- /auth/error     authorization failed
Mirror the Cloudflare OAuth flow for PlanetScale. `alchemy login` now
offers a browser-based OAuth method alongside env + service tokens.

- OAuthClient.ts: authorize/exchange/refresh/callback over a localhost
  loopback (redirect URI http://localhost:9976/auth/callback), landing on
  the shared /auth/success + /auth/error pages.
- AuthProvider.ts: `oauth` method wired through configure/login/resolve
  (with proactive refresh)/logout/prettyPrint.
- Credentials.ts: resolves OAuth creds to a Bearer token.

PlanetScale has no PKCE flow, so the app client_secret ships in the CLI
(same exposure as a public client_id; rotate via release). Scopes are
configured on the OAuth app, not requested per-authorization, and there
is no token-revocation endpoint so logout just drops local tokens.

Depends on Bearer support in @distilled.cloud/planetscale
(alchemy-run/distilled#311) — catalog temporarily points at the branch
build; repoint to the released version before merge.
End-to-end fixes for the PlanetScale OAuth flow after testing against
the live auth server:

- `authorize()` now sends `response_type=code` (PlanetScale rejects the
  request without it — "Missing required parameter: response_type").
- Scope names must carry tier prefixes (`user:`, `organization:`,
  `database:`, `branch:`) — bare `read_user` etc. are rejected with
  "The requested scope is invalid, unknown, or malformed." The public
  docs page's section headers are literally part of the scope id, not
  groupings. ALL_SCOPES now mirrors PlanetScale's full prefixed list
  (plus the OIDC trio); DEFAULT_SCOPES covers what Alchemy resources
  actually need.
- Empty `scopes` skips the `scope=` param entirely so the user falls
  back to PlanetScale's implicit defaults.
- Real OAuth app credentials baked in (replaces placeholders).
- Credentials.ts annotates the Effect.map return as `Config` so the
  oauth | apiToken branches resolve cleanly against the distilled
  `ServiceTokenConfig | OAuthConfig` union.

Verified: `alchemy login` opens consent, callback completes, tokens
land in the store with the requested prefixed scopes.
@Mkassabov Mkassabov marked this pull request as ready for review June 5, 2026 21:54
Comment on lines +41 to +42
export const OAUTH_CLIENT_SECRET =
"pscale_app_secret_yyZ3Q8oe99GP9_yA5wrA5er6RuN6Lz9dC66Bj1OJzpg";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this safe to check in?

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