feat/google-oauth-and-dev-naming #8

Merged
vas2000-work merged 4 commits from feat/google-oauth-and-dev-naming into main 2026-05-07 01:50:30 +02:00
Owner
No description provided.
Drop the redundant `mokosh-` segment from the compose service key (the project name `dev-mokosh` already carries the app name; the final container name remains `dev-mokosh-server-${USER}`). Add an explicit `container_name:` to every service so the user postfix lands consistently when multiple developers share a host, and append matching `-${USER}` suffixes to every volume and to the private network. The justfile `dev` recipe now captures `whoami` and writes `USER=...` into .env so subsequent compose commands (down/clean) see the same value.

This is the rename half of the feat/google-oauth-and-dev-naming branch; OAuth changes follow in a separate commit on top.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New routes `/api/v1/auth/google` and `/api/v1/auth/google/callback` open the user in a Google consent popup; the callback page closes itself and `postMessage`s the JWT response back to the SPA opener. Open auto-provision: any verified Google email becomes a user under the default tenant on first login. Domains in `OAUTH_SUPER_ADMIN_DOMAINS` (default `niceguyit.biz`) are auto-promoted to `role = super_admin` on first provisioning only - existing users keep their role.

The OAuth primitives live in a new reusable workspace crate `google-oauth-flow` (path: crates/google-oauth-flow). It takes only env-driven config (`GOOGLE_OAUTH_CLIENT_ID` / `_SECRET` / `_REDIRECT_URI`) and exposes a small typed API (`Config::from_env`, `Client::new`, `Client::build_authorize_url`, `Client::exchange_code` returning `GoogleUserInfo`). No web framework, no DB, no JWT-secret coupling - drop into another project as-is.

Networking reshape: the API now publishes on host `MOKOSH_API_HOST_PORT` (default 4302) so the client SPA can keep host port 4301. The matching `[[web.proxy]]` lands on the mokosh-clients side so the SPA and API share a browser-visible origin in dev (required for the popup + postMessage same-origin check; Google also rejects plain HTTP redirect URIs on non-loopback hosts so dev access must go through `localhost`).

State (CSRF + PKCE verifier) between the authorize redirect and the callback rides in a `JWT_SECRET`-signed, `HttpOnly`, `SameSite=Lax`, 10-min cookie scoped to the callback path. Cookie signing is mokosh's responsibility (in `src/modules/auth/google_login.rs`) so the crate stays JWT-secret-unaware.

New migration `003_user_oauth_identities.sql` links Google's stable `sub` claim to a Mokosh user so an email change on the Google side does not orphan the link. The existing `users` schema was already OAuth-ready (`password_hash` and `email_verified_at` are nullable).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The OAuth verification was blocked by a cascade rooted in the host-postgres dependency: dev-mokosh-server-${USER} would panic on startup with "Failed to connect to database: Network is unreachable" because it was trying to reach a host PostgreSQL via host.docker.internal, which either was not running or not bound to the docker bridge. Because the server container exited, the compose network had no `server` DNS entry, and the Dioxus dev-server proxy (`/api/*` -> `http://server:4301/`) failed with "Name or service not known", surfacing as the OAuth popup error.

Move the app DB into compose as a new top-level `postgres` service named `dev-mokosh-postgres-${USER}`, published to the host on `${MOKOSH_HOST_BIND_IP}:${MOKOSH_PG_HOST_PORT:-5433}` so `sqlx-cli` (host-side) still works. The server reaches it via in-network DNS at `postgres:5432`. `DATABASE_URL_IN_CONTAINER` and the `host.docker.internal` `extra_hosts` entry are removed; the container-side DSN is composed inline in compose.dev.yml from MOKOSH_PG_*. .env.dev / .env.example / README.md updated.

Also folds in the Dockerfile + crates volume fixes for the new `google-oauth-flow` workspace member: cache layer now copies `crates/google-oauth-flow/Cargo.toml` and stubs an empty `lib.rs` so cargo can resolve the workspace before sources are mounted, and compose mounts `./crates` at runtime. Cargo.lock updated for the OAuth dep tree (oauth2, cookie, thiserror).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
fix: axum 0.8 path syntax, ConnectInfo wiring, fresh-build Dockerfile
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
3c06b462ab
Three small follow-ups discovered during OAuth end-to-end verification:

- Convert all `:param` route segments to `{param}`. Adding `oauth2` re-resolved Cargo.lock and bumped axum to 0.8.9, which (unlike 0.8.3 used previously) panics on the legacy 0.7-style colon-prefixed capture syntax. Affected: src/api/router.rs, src/modules/auth/routes.rs, src/modules/contacts/routes.rs, src/modules/tenants/routes.rs, src/modules/tickets/routes.rs.
- Switch `axum::serve(listener, router)` to `axum::serve(listener, router.into_make_service_with_connect_info::<SocketAddr>())` so the existing `ConnectInfo<SocketAddr>` extractors in `login` and the new `google_callback` actually resolve. Without this the OAuth callback returns 500 with "Missing request extension: Extension of type ConnectInfo... was not found".
- Strip the dependency-cache pre-build step from the dev Dockerfile. The stub-source pre-build was leaving `target/` fingerprints that confused cargo into a no-op rebuild on first container start (silent exit 0 with no output). Container start now does a single ~45s full compile against bind-mounted source; the persisted target volume caches it for subsequent restarts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
vas2000-work deleted branch feat/google-oauth-and-dev-naming 2026-05-07 01:50:30 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!8
No description provided.