Skip to content

Commit 65429fc

Browse files
authored
docs: testing EVE SSO and Discord linking over a tunnel (#21)
Stage 4, documentation only. The seeded cookie from Stage 3 covers most dev work; this covers the case it cannot — changing the login or character-link flows themselves, which needs the real providers to redirect back to your machine. Every concrete claim was verified against the code rather than described from memory: - Redirect URIs are string-concatenated, not URL-joined, so a trailing slash on APP_BASE_URL yields `//auth/eve/callback` and z.string().url() accepts it silently — it surfaces much later as an unexplained redirect mismatch. - One EVE entry covers both flows: /auth/eve/login and /auth/eve/link both call buildEveAuthorizeUrl, so they share /auth/eve/callback. - EVE sends redirect_uri only on authorize; exchangeEveCode sends grant_type, code and code_verifier. Discord sends it TWICE — authorize and token exchange — and they must match. Changing APP_BASE_URL mid-flow therefore breaks Discord linking while EVE login keeps working, which reads like a Discord outage and is not. - Once APP_BASE_URL is https the session cookie is issued Secure, so the browser will not return it over http://localhost — you appear logged out no matter how often you log in. Browse the tunnel origin. Recommends .env.local for the override: it wins over .env, .env* is gitignored apart from .env.example, and switching back is deleting one file.
1 parent 935d750 commit 65429fc

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

docs/ops.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,91 @@ Two behaviors worth knowing:
418418
Character ids come from a reserved `91_000_0xx` block, chosen to sit clear of
419419
the `90_000_0xx` ids the e2e suite generates, so the two can never collide.
420420

421+
### Real OAuth locally, over a tunnel
422+
423+
The seeded cookie above covers most dev work. You need real OAuth only when you
424+
are changing the login or character-link flows themselves.
425+
426+
Both providers redirect back to a URL derived from `APP_BASE_URL`, so they have
427+
to reach your machine. A tunnel with a **stable** domain is what makes this
428+
bearable — a fresh random hostname per run means re-registering the redirect URI
429+
in two developer portals every time.
430+
431+
#### 1. Start the tunnel
432+
433+
```bash
434+
ngrok http 3000 --domain your-stable-domain.ngrok-free.app
435+
```
436+
437+
#### 2. Override `APP_BASE_URL` in `.env.local`
438+
439+
`.env.local` wins over `.env` (both are loaded, later file first), and `.env*` is
440+
gitignored apart from `.env.example`. Keeping the override in a second file means
441+
your working `.env` stays untouched and switching back is deleting one file.
442+
443+
```bash
444+
# .env.local — tunnelled OAuth. Delete this file to go back to localhost.
445+
APP_BASE_URL=https://your-stable-domain.ngrok-free.app
446+
```
447+
448+
**No trailing slash.** The value is string-concatenated, not URL-joined, and
449+
`z.string().url()` accepts a trailing slash happily — so it fails much later, as
450+
an unexplained redirect-URI mismatch:
451+
452+
```text
453+
APP_BASE_URL=https://x.ngrok.app → https://x.ngrok.app/auth/eve/callback
454+
APP_BASE_URL=https://x.ngrok.app/ → https://x.ngrok.app//auth/eve/callback ✗
455+
```
456+
457+
#### 3. Register the redirect URIs
458+
459+
Exactly two, and they must match character-for-character:
460+
461+
| Provider | Redirect URI to register |
462+
|---|---|
463+
| EVE (developers.eveonline.com → your application) | `https://your-stable-domain.ngrok-free.app/auth/eve/callback` |
464+
| Discord (Developer Portal → your app → OAuth2 → Redirects) | `https://your-stable-domain.ngrok-free.app/auth/discord/callback` |
465+
466+
**One EVE entry covers both flows.** Login (`/auth/eve/login`) and adding a
467+
character (`/auth/eve/link`) both call `buildEveAuthorizeUrl`, so they share the
468+
single `/auth/eve/callback` URI. Discord needs only `identify` scope.
469+
470+
#### 4. Browse the tunnel URL, not localhost
471+
472+
Once `APP_BASE_URL` is `https://…`, the session cookie is issued with `Secure`
473+
(`src/app/auth/eve/callback/route.ts`), so the browser will not send it back over
474+
plain `http://localhost:3000`. You will appear logged out no matter how many
475+
times you log in. Use the tunnel origin for the whole session.
476+
477+
This applies to seeded cookies too: paste them on the origin you are browsing,
478+
and mark them `Secure` when that origin is https.
479+
480+
#### The failure that looks like a Discord bug
481+
482+
EVE and Discord treat `redirect_uri` differently, and it matters when you change
483+
`APP_BASE_URL`:
484+
485+
- **EVE** sends `redirect_uri` only on the authorize request. The token exchange
486+
(`exchangeEveCode`, `src/lib/esi/sso.ts`) sends `grant_type`, `code`, and
487+
`code_verifier` — no `redirect_uri`.
488+
- **Discord** sends it **twice** — on authorize *and* again in the token exchange
489+
(`src/lib/discord/oauth.ts`), where it must match the first one exactly.
490+
491+
So if you change `APP_BASE_URL` (or restart the server with a different tunnel
492+
domain) *between* clicking "link Discord" and the redirect landing, the exchange
493+
fails while EVE login keeps working. It reads like a Discord outage; it is a
494+
mid-flight config change. Restart the flow from the current origin.
495+
496+
#### Switching back to localhost
497+
498+
```bash
499+
rm .env.local # or comment out the APP_BASE_URL line
500+
```
501+
502+
Restart `npm run dev``.env.local` is read at process start, not per request.
503+
The registered tunnel redirect URIs can stay in both portals; they are inert
504+
while `APP_BASE_URL` points at localhost, so this is a one-line round trip.
505+
421506
### Expected noise
422507

423508
`--env-file-if-exists` prints one line per missing file, and `tsx` re-execs

0 commit comments

Comments
 (0)