stack/docs-mintlify/migration.mdx
BilalG1 fa2baa829d
feat(oauth): per-provider customCallbackUrl for redirect_uri (#1512)
## Summary

Replaces the request-host-header-derived OAuth `redirect_uri` with a
config-driven `customCallbackUrl` field on each environment-level OAuth
provider.

Resolution of the `redirect_uri` we send to providers (and that
customers register in their provider app config):

- **Shared providers** → always the stack-auth-branded callback, so
Stack's shared OAuth apps keep working. `customCallbackUrl` is
schema-forbidden when `isShared` is true.
- **Custom + `customCallbackUrl` set** → the configured URL verbatim.
- **Custom without it (legacy)** → the stack-auth-branded callback, so
providers registered before this field are unaffected.
- **New custom providers set up in the dashboard** → the env-aware
hexclave-branded callback (prod → `api.hexclave.com`, dev/staging →
siblings, self-host/localhost → `NEXT_PUBLIC_STACK_API_URL` unchanged).

## Details

- **Schema** (`schema.ts`, `schema-fields.ts`): optional
`customCallbackUrl` after `clientSecret`, with a `.when('isShared')`
rule rejecting any value for shared providers; added to the provider
default factory.
- **Shared host helper** (`utils/cloud-hosts.tsx`, new):
`CLOUD_HOST_PAIRS` moved into stack-shared with `getCloudApiUrlSiblings`
/ `getStackAuthApiBaseUrl` / `getHexclaveApiBaseUrl`;
`request-api-url.ts` re-exports it so the JWT `iss` logic is untouched.
- **Runtime** (`oauth/index.tsx` + all 13 provider `create()`s):
`getProvider` resolves the full `redirect_uri` from config instead of
the request host; providers now take `redirectUri` instead of `apiUrl`.
The JWT `iss` path still uses the request host.
- **Dashboard** (`page-client.tsx`, `providers.tsx`,
`oauth-callback-url.ts` new): brand-new custom providers get the
hexclave callback; existing providers keep whatever they had (edits
never silently move a registered redirect URL); the displayed Redirect
URL mirrors backend resolution.
- **Docs** (`migration.mdx`): existing `api.stack-auth.com` callbacks
keep working; only recreated providers use the hexclave URL.

## Notes / scope decisions

- **Dashboard-only injection**: SDK/CLI/legacy-config-created custom
providers fall back to the stack-auth callback (they don't auto-get the
hexclave URL).
- **shared → standard** conversions keep the stack-auth fallback rather
than flipping to hexclave (the safe path that never breaks a registered
redirect).

## Test plan

- [x] `typecheck` + `lint` green across stack-shared, backend,
dashboard, e2e
- [x] cloud-hosts unit tests, schema tests, schema fuzzer pass
- [x] e2e: shared-provider `customCallbackUrl` rejected (400);
standard-provider `customCallbackUrl` accepted and round-trips
- [ ] e2e OAuth authorize/callback flow (needs running stack) — reasoned
unaffected since localhost isn't a cloud host, so the redirect base
stays localhost as before

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a per-provider `customCallbackUrl` for OAuth `redirect_uri`,
removing the request-host dependency and making redirects predictable.
Shared providers always use the Stack-branded callback; new or converted
custom providers default to the Hexclave-branded callback. Existing
callbacks keep working; no changes needed unless you recreate or convert
a provider.

- **New Features**
- Added `customCallbackUrl` on provider configs (URL-validated;
forbidden when `isShared` is true).
- `getProvider` now resolves a config-driven `redirectUri`; providers
take `redirectUri` instead of `apiUrl` (pure resolver with in-source +
e2e tests to lock legacy behavior).
- Introduced `@stackframe/stack-shared` `utils/cloud-hosts.tsx` and
dashboard helpers to show the resolved Redirect URL and set the Hexclave
callback for new providers and when converting shared → standard.

- **Bug Fixes**
- OAuth callback now handles legitimate cross-host flows by recording
the authorize host and skipping the host-scoped CSRF cookie when
authorize and callback hosts differ, relying on server-side state and
PKCE.

<sup>Written for commit 32d95fcdcb.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/stack-auth/pull/1512?utm_source=github">Review
in cubic</a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Preserve and display custom OAuth callback/redirect URLs in the
dashboard; provider creation/edit flows respect existing custom URLs.
* Added cloud-host mapping and redirect-uri helpers to resolve branded
API callback bases.

* **Bug Fixes**
* Improved cross-host OAuth callback handling and CSRF validation for
reliable cross-host flows.

* **Tests**
* Added E2E and unit tests covering callback URL behavior and host
mapping.

* **Documentation**
* Updated migration guidance for callback URL changes and recreation
scenarios.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1512?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-28 12:28:38 -07:00

79 lines
2.9 KiB
Plaintext

---
title: Migrating from Stack Auth to Hexclave
description: How to migrate your application from the legacy @stackframe/* packages to @hexclave/*.
sidebarTitle: Migration
---
Stack Auth is now Hexclave. The dashboard, APIs, and your data are unchanged — only the brand and the package names changed. Both backends (`api.stack-auth.com` and `api.hexclave.com`) point at the same service, so each `@stackframe/*` package continues to work; staying on the legacy SDK requires no action.
This guide is for projects that want to migrate to `@hexclave/*` packages.
## 1. Install the new packages
Replace each `@stackframe/*` dependency with its `@hexclave/*` equivalent:
```bash
npm uninstall @stackframe/stack
npm install @hexclave/next
```
| Old package | New package |
| --- | --- |
| `@stackframe/stack` | `@hexclave/next` |
| `@stackframe/react` | `@hexclave/react` |
| `@stackframe/js` | `@hexclave/js` |
Rename your imports from `@stackframe/*` to `@hexclave/*`. The public API surface is identical, except that all `Stack*` references are renamed to `Hexclave*`:
```ts title="Before"
import { StackClientApp, StackProvider, useStackApp } from "@stackframe/stack";
```
```ts title="After"
import { HexclaveClientApp, HexclaveProvider, useHexclaveApp } from "@hexclave/next";
```
## 2. Update hardcoded references
Sweep your codebase and replace:
- `https://api.stack-auth.com` → `https://api.hexclave.com`
## Optional changes
All legacy names keep working — rename only if you want your code to match the new brand.
- **Request headers**: `X-Stack-*` → `X-Hexclave-*`.
- **Environment variables**: `STACK_*` → `HEXCLAVE_*`.
- **Bearer prefix**: `stackauth_*` tokens remain valid.
- **CLI binary**: both `stack` and `hexclave` ship with `@hexclave/cli`.
- **Hosted-handler subdomain**: `.built-with-stack-auth.com` still works.
## Other
If your backend verifies Hexclave-issued JWTs directly (for example with `jose.jwtVerify`), update the expected `iss` claim — `@hexclave/*` SDKs sign tokens under the hexclave host:
```ts title="Before"
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: 'https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID',
audience: 'YOUR_PROJECT_ID',
});
```
```ts title="After"
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: 'https://api.hexclave.com/api/v1/projects/YOUR_PROJECT_ID',
audience: 'YOUR_PROJECT_ID',
});
```
The same applies to the anonymous (`/api/v1/projects-anonymous-users/...`) and restricted (`/api/v1/projects-restricted-users/...`) issuer variants.
You don't need to update your OAuth provider callback URLs — your current `api.stack-auth.com` callback URLs keep working. However, if you recreate an OAuth provider on the dashboard, you'll need to use the new callback URL:
```
https://api.hexclave.com/api/v1/auth/oauth/callback/<provider>
```
Questions? [Discord](https://discord.hexclave.com) or [team@hexclave.com](mailto:team@hexclave.com).