# Local subdomain routing for provider login

Customer Connect supports logging into a specific provider's tenant by visiting
`<provider>.<baseDomain>` (e.g. `acme.staging-connect.netfoundry.io`). The
console reads the subdomain and pins the OAuth flow to that tenant. See
`src/lib/shared/provider-override.util.ts` and `src/environments/*.ts`
(`tenant.baseDomain`).

This document covers the one-time local setup needed to test that flow on
`*.local-connect.dev:4300` instead of having to deploy. The setup is opt-in:
the existing `npm run start:localhost` keeps serving HTTP on plain `localhost`,
and the new `npm run start:local-connect` brings up the HTTPS-with-wildcard
mode described below.

## Why bother with HTTPS + wildcard DNS

Auth0 enforces two rules on the `redirect_uri` it accepts:

- The URL must appear in **Allowed Callback URLs** on the application.
- Wildcards (`*`) are only allowed as the leftmost subdomain **and only on
  HTTPS hostnames** — `http://*.localhost:4300/callback` is rejected.

So to test arbitrary `<provider>.<host>` labels locally without enumerating
every provider in Auth0, you need:

1. A wildcard DNS entry that resolves `*.local-connect.dev` to `127.0.0.1`.
2. A trusted HTTPS cert for `*.local-connect.dev` so the dev server doesn't
   throw cert warnings.
3. A single wildcard registration in the Auth0 application:
   `https://*.local-connect.dev:4300/callback`.

`local-connect.dev` is just a convention — pick a TLD you don't own (`.dev`,
`.test`, `.local` are common). If you change it, change `baseDomain` in
`src/environments/environment.local-connect.ts` and the cert / Auth0 wildcards
below to match.

## One-time host setup

### 1. Wildcard DNS via `dnsmasq`

macOS supports per-TLD resolvers, so you can route every `*.local-connect.dev`
lookup to a local dnsmasq instance without ever editing `/etc/hosts`.

```bash
brew install dnsmasq

# Tell dnsmasq to answer every *.local-connect.dev with 127.0.0.1
echo "address=/local-connect.dev/127.0.0.1" >> /opt/homebrew/etc/dnsmasq.conf

# Start dnsmasq as a launchd service (sudo because it binds to port 53)
sudo brew services start dnsmasq

# Tell macOS to use that local dnsmasq for the .local-connect.dev TLD
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/local-connect.dev
```

> Intel Macs: use `/usr/local/etc/dnsmasq.conf` instead of `/opt/homebrew/etc/...`.

Verify:

```bash
dscacheutil -q host -a name acme.local-connect.dev   # → 127.0.0.1
ping -c 1 demo.local-connect.dev                     # → 127.0.0.1
```

### 2. Trusted local TLS via `mkcert`

```bash
brew install mkcert nss

# Install mkcert's local CA into your system + browser trust stores.
# This is the one step that REQUIRES an interactive terminal — it shells out
# to `sudo security add-trusted-cert` and needs your password.
mkcert -install

# Create the wildcard cert inside the repo's gitignored `dev-certs/` dir so
# `angular.json` can reference it via a stable relative path.
mkdir -p dev-certs && cd dev-certs
mkcert "*.local-connect.dev" "local-connect.dev"
cd ..
```

That writes `dev-certs/_wildcard.local-connect.dev+1.pem` (cert) and
`dev-certs/_wildcard.local-connect.dev+1-key.pem` (key). The folder is
gitignored, so each developer keeps their own certs.

> **Restart any open browsers** after `mkcert -install`. Chrome / Brave cache
> the trust store on startup; running browsers will keep showing
> `NET::ERR_CERT_AUTHORITY_INVALID` until you quit and reopen.

### 3. Auth0 application settings

In the Auth0 dashboard, on the customer-connect-console application
(staging-tenant client `aB3mXNagA93HxhDNRCssXnfTNzXs64iP`), add the wildcard
entries to **all three** allow-lists (each must include the URL — Auth0
checks them independently):

```
Allowed Callback URLs:
  https://*.local-connect.dev:4300/callback
  https://*.staging-connect.netfoundry.io/callback
  https://*.sandbox-connect.netfoundry.io/callback
  https://*.connect.netfoundry.io/callback

Allowed Web Origins:
  https://*.local-connect.dev:4300
  https://*.staging-connect.netfoundry.io
  https://*.sandbox-connect.netfoundry.io
  https://*.connect.netfoundry.io

Allowed Logout URLs:
  https://*.local-connect.dev:4300
  https://*.staging-connect.netfoundry.io
  https://*.sandbox-connect.netfoundry.io
  https://*.connect.netfoundry.io
```

Auth0 only allows `*` as the leftmost subdomain (and only on HTTPS), which is
why these entries are valid but `http://*.localhost:4300/callback` is not.
One wildcard per environment covers every provider label, so you don't need
to revisit Auth0 when you add a new tenant.

## Running the dev server over HTTPS

The `local-connect` configuration in `angular.json` already wires:

- `ssl: true`
- `sslCert: dev-certs/_wildcard.local-connect.dev+1.pem`
- `sslKey:  dev-certs/_wildcard.local-connect.dev+1-key.pem`
- `host: 0.0.0.0`, `port: 4300`
- File replacement to `src/environments/environment.local-connect.ts`
  (`baseDomain: 'local-connect.dev'`)

So once dnsmasq is running and the cert files are in `dev-certs/`, just:

```bash
npm run start:local-connect
```

**Make sure no other dev server is already on 4300** — `npm run start` and
`npm run start:localhost` both bind that port over plain HTTP, and visiting
`https://…:4300` against an HTTP server gives `ERR_SSL_PROTOCOL_ERROR`. If
you have one running, stop it first.

The original `npm run start:localhost` continues to serve plain HTTP on
`http://localhost:4300` for anyone who doesn't want the subdomain mode.

## Daily use

Once everything is set up, visit any of these in a browser:

- `https://local-connect.dev:4300` → default tenant (NFADMIN).
- `https://acme.local-connect.dev:4300` → `acme` tenant.
- `https://anything.local-connect.dev:4300` → `anything` tenant.

The full priority chain is:

1. `?provider=` query param (explicit override beats subdomain).
2. Stashed `?provider=` from the post-login redirect.
3. **Subdomain** (what this doc enables).
4. `sessionStorage['cc.providerOverride']` (persisted from a prior resolution).

Anything that isn't a valid provider label on the staging tenant will end up
at the "We couldn't finish signing you in" screen.

## Stopping / cleanup

```bash
sudo brew services stop dnsmasq      # turn off the local resolver
sudo rm /etc/resolver/local-connect.dev
brew uninstall dnsmasq mkcert        # if you want them gone entirely
mkcert -uninstall                    # removes the local CA from trust store
```

## Troubleshooting

- **`ping local-connect.dev` works but `ping acme.local-connect.dev` doesn't**
  → dnsmasq isn't running (`sudo brew services list`) or the resolver file
  isn't in `/etc/resolver/`. Restart with `sudo brew services restart dnsmasq`.
- **`ERR_SSL_PROTOCOL_ERROR`** → the server on 4300 is serving plain HTTP.
  Either the `local-connect` dev server isn't actually running (cert paths
  missing → check `ls dev-certs/`), or a different `ng serve` is on 4300.
  Stop everything (`lsof -nP -iTCP:4300 -sTCP:LISTEN`, kill the PID), then
  `npm run start:local-connect`.
- **`NET::ERR_CERT_AUTHORITY_INVALID` / "Your connection is not private"** →
  `mkcert -install` wasn't run, OR your browser was open during install and
  cached the empty trust store. Run `mkcert -install` from a real terminal
  (it needs sudo), then fully **quit** Chrome / Brave / Firefox and reopen.
  For Firefox specifically, the `nss` package must be installed (`brew install
  nss && mkcert -install`).
- **`Callback URL mismatch` from Auth0** → the wildcard URLs above weren't
  saved on the Auth0 application. Double-check Allowed Callback URLs (and
  Allowed Web Origins, and Allowed Logout URLs — Auth0 checks all three).
- **`consent_required` after credentials** → the user really doesn't have
  access to the requested provider tenant. Try with a tenant the user is a
  member of. If it happens for the env-default (NFADMIN) tenant too, the
  auth flow itself is broken — see `src/lib/features/auth/callback.component.ts`
  and the resume-via-`/continue` notes there.
