feature/fix-deployment-script
claude/smbcloud-github-app-k9641p
development
feature/apps
feature/build-release
feature/ci-docs
feature/ci-ruby-gems
feature/cicd
feature/completion
feature/dist-nuget
feature/fix-ci-sdk-pypi-rubygem
feature/fix-clippy-on-stable-channel
feature/fix-deployment-script
feature/github-email
feature/gresiq-v1
feature/project-new-structure
feature/rsync-deploy
feature/ruby-runner
feature/sdk-npm
feature/sdk-workflows
feature/smbcloud-cli-release-npm
feature/smbcloud-deploy
feature/wasm
main
release/v0.7.4
| 1 | --- |
| 2 | name: smbcloud-auth |
| 3 | description: Use when building, debugging, or extending smbCloud authentication across the Rails auth service, the web console, the Rust or WASM auth SDKs, and Tauri or web client apps. Covers platform clients vs tenant auth apps, AuthUser signup/sign-in/confirmation, OAuth providers for AuthUser, shared auth apps across projects, browser SDK integration, and development vs production app credentials. |
| 4 | --- |
| 5 | |
| 6 | # smbCloud Auth |
| 7 | |
| 8 | Use this skill when work touches any part of the smbCloud auth stack: |
| 9 | |
| 10 | - `smbcloud-api` Rails auth service |
| 11 | - `smbcloud-web-console` Next.js admin UI |
| 12 | - `smbcloud-cli/crates/smbcloud-auth` Rust SDK |
| 13 | - `smbcloud-cli/crates/smbcloud-auth-sdk-wasm` browser SDK |
| 14 | - Tauri apps such as Rumi Learn Persian and PBJ Komplit |
| 15 | - web apps that use `@smbcloud/sdk-auth` |
| 16 | |
| 17 | ## Core model |
| 18 | |
| 19 | There are two auth planes. Do not mix them. |
| 20 | |
| 21 | ### 1. Platform clients |
| 22 | |
| 23 | These are smbCloud's own apps: |
| 24 | |
| 25 | - `web` |
| 26 | - `cli` |
| 27 | - `sigit` |
| 28 | - `moovibe` |
| 29 | - `webconsole` |
| 30 | |
| 31 | They authenticate smbCloud operator users through platform endpoints such as: |
| 32 | |
| 33 | - `POST /v1/users/sign_in` |
| 34 | - `POST /v1/users` |
| 35 | |
| 36 | They must use the platform client validator, not tenant app validation. |
| 37 | |
| 38 | ### 2. Tenant auth apps |
| 39 | |
| 40 | These are customer-facing apps such as Rumi or PBJ Komplit. |
| 41 | |
| 42 | They authenticate end users through: |
| 43 | |
| 44 | - `POST /v1/client/users` |
| 45 | - `POST /v1/client/users/sign_in` |
| 46 | - `GET /v1/client/me` |
| 47 | - `DELETE /v1/client/me` |
| 48 | - `DELETE /v1/client/users/sign_out` |
| 49 | - `GET /v1/client/users/confirmation` |
| 50 | |
| 51 | The tenant auth domain is: |
| 52 | |
| 53 | - `AuthApp` |
| 54 | - `AuthAppSecret` |
| 55 | - `AuthUser` |
| 56 | |
| 57 | Tenant apps must use `AuthAppClientAuthenticatable` and must not go through platform `/v1/users`. |
| 58 | |
| 59 | ### Provider auth boundary |
| 60 | |
| 61 | OAuth providers such as Apple or Google for customer apps belong to the tenant auth plane: |
| 62 | |
| 63 | - provider sign-in for end users must resolve to `AuthUser` |
| 64 | - provider linkage must be scoped to `AuthApp` |
| 65 | - the result must be the same tenant auth session shape used by email/password |
| 66 | |
| 67 | Do not route tenant provider auth through: |
| 68 | |
| 69 | - platform `User` |
| 70 | - `Authorization` records for platform users |
| 71 | - Doorkeeper/OIDC smbCloud internal users |
| 72 | |
| 73 | If provider support is added for tenant apps, the backend contract should end in an `AuthUser` session or JWT, not a provider token as the primary app session. |
| 74 | |
| 75 | ## Multi-project auth apps |
| 76 | |
| 77 | Current rule: |
| 78 | |
| 79 | - one `AuthApp` has an owner project via `auth_apps.project_id` |
| 80 | - one `AuthApp` can be shared with other projects through `auth_app_projects` |
| 81 | - one project can point to only one auth app |
| 82 | |
| 83 | If a workspace/project should reuse an existing auth app, attach it instead of creating a duplicate. |
| 84 | |
| 85 | ## Rails conventions |
| 86 | |
| 87 | When editing `smbcloud-api`: |
| 88 | |
| 89 | - Platform operator auth stays under `User` |
| 90 | - Tenant app auth stays under `AuthUser` |
| 91 | - Do not reuse `OauthApplication` for tenant end-user login |
| 92 | - Do not hardcode tenant app validation in platform controllers |
| 93 | |
| 94 | ### Tenant provider auth modeling |
| 95 | |
| 96 | If tenant users need Apple, Google, or other OAuth providers: |
| 97 | |
| 98 | - add provider linkage for `AuthUser`, not platform `User` |
| 99 | - model by stable provider subject, not by email |
| 100 | - keep provider records scoped to the tenant auth app |
| 101 | |
| 102 | Preferred shape: |
| 103 | |
| 104 | - `AuthUserAuthorization` |
| 105 | - `auth_user_id` |
| 106 | - `provider` |
| 107 | - `uid` |
| 108 | - optional `email` |
| 109 | - optional `raw_profile` |
| 110 | |
| 111 | For Apple specifically: |
| 112 | |
| 113 | - use Apple `sub` as the stable provider identity |
| 114 | - do not treat email as the primary key |
| 115 | - do not assume name is available after first sign-in |
| 116 | |
| 117 | The Rails backend should verify provider assertions and then mint the normal tenant auth session for the resolved `AuthUser`. |
| 118 | |
| 119 | ### AuthUser signup/sign-in rules |
| 120 | |
| 121 | - Signup creates an `AuthUser` scoped to `current_auth_app` |
| 122 | - Signup sends confirmation email |
| 123 | - Do not auto-set `confirmed_at` |
| 124 | - Sign-in returns `EmailNotVerified` until email is confirmed |
| 125 | - Deletion removes the currently authenticated `AuthUser` |
| 126 | |
| 127 | ### Mail flow |
| 128 | |
| 129 | For tenant users, use the explicit confirmation flow already established: |
| 130 | |
| 131 | - custom mailer for `AuthUser` |
| 132 | - confirmation link to `/v1/client/users/confirmation?confirmation_token=...` |
| 133 | |
| 134 | Do not claim email confirmation exists unless the mailer and route are actually wired. |
| 135 | |
| 136 | ## Rust SDK conventions |
| 137 | |
| 138 | The Rust client surface lives in: |
| 139 | |
| 140 | - `smbcloud-cli/crates/smbcloud-auth` |
| 141 | - `smbcloud-cli/crates/smbcloud-auth-sdk-wasm` |
| 142 | |
| 143 | When changing tenant app auth: |
| 144 | |
| 145 | - keep tenant auth on `/v1/client/*` |
| 146 | - preserve `AccountStatus` mapping: |
| 147 | - `NotFound` |
| 148 | - `Ready { access_token }` |
| 149 | - `Incomplete { status }` |
| 150 | - `request_login` depends on `422` + `error_code` for incomplete accounts |
| 151 | |
| 152 | If the backend changes error shape or status codes, update the Rust parser accordingly. |
| 153 | |
| 154 | ### Browser/WASM SDK conventions |
| 155 | |
| 156 | The browser package is consumed as `@smbcloud/sdk-auth`. |
| 157 | |
| 158 | Current exported surface includes: |
| 159 | |
| 160 | - `signup_with_client` |
| 161 | - `login_with_client` |
| 162 | - `me_with_client` |
| 163 | - `logout_with_client` |
| 164 | - `remove_with_client` |
| 165 | - `Environment.Dev` |
| 166 | - `Environment.Production` |
| 167 | |
| 168 | Recommended browser integration pattern: |
| 169 | |
| 170 | - lazy-load the WASM runtime with `await import("@smbcloud/sdk-auth")` |
| 171 | - call `await runtime.default()` before using the exported functions |
| 172 | - store only the access token in browser storage |
| 173 | - restore the session with `me_with_client` |
| 174 | - gate environment switching behind explicit debug controls |
| 175 | |
| 176 | Do not build browser flows around NextAuth sessions if the product session is actually an smbCloud `AuthUser` token. The browser app should either: |
| 177 | |
| 178 | - use the browser SDK directly for email/password flows, or |
| 179 | - complete provider auth through Rails and then store the resulting tenant auth token |
| 180 | |
| 181 | ## Tauri client conventions |
| 182 | |
| 183 | For Rumi/PBJ-style apps: |
| 184 | |
| 185 | - use a dedicated `src-tauri/src/smbcloud/mod.rs` |
| 186 | - expose commands for: |
| 187 | - `signup_user` |
| 188 | - `sign_in_user` |
| 189 | - `current_user` |
| 190 | - `sign_out_user` |
| 191 | - `delete_current_user` |
| 192 | - `is_debug_build` |
| 193 | - store auth state in plugin-store: |
| 194 | - access token |
| 195 | - provider |
| 196 | - auth environment |
| 197 | - language |
| 198 | |
| 199 | ### Environment handling |
| 200 | |
| 201 | Keep development and production app credentials separate. |
| 202 | |
| 203 | Preferred pattern: |
| 204 | |
| 205 | - development credentials for local auth service |
| 206 | - production credentials for hosted auth service |
| 207 | - switch via a Rust `AuthEnvironment` enum |
| 208 | - expose the switch in debug builds only |
| 209 | |
| 210 | Recommended env variable names: |
| 211 | |
| 212 | - `SMBCLOUD_APP_ID_DEV` |
| 213 | - `SMBCLOUD_APP_SECRET_DEV` |
| 214 | - `SMBCLOUD_APP_ID_PRODUCTION` |
| 215 | - `SMBCLOUD_APP_SECRET_PRODUCTION` |
| 216 | |
| 217 | ### Public-client security rule |
| 218 | |
| 219 | Tauri, mobile, and browser apps are public clients. Treat `app_id` as public and `app_secret` as non-confidential if it is shipped in a client binary or browser bundle. |
| 220 | |
| 221 | Implications: |
| 222 | |
| 223 | - do not claim the client app secret is secure once distributed |
| 224 | - do not rely on embedded `app_secret` as the main client authentication boundary |
| 225 | - prefer backend-mediated flows, PKCE, or other public-client-safe patterns for stronger security |
| 226 | |
| 227 | If the current SDK or API still requires `app_secret` from public clients, call out that limitation explicitly in code review or implementation notes. |
| 228 | |
| 229 | ### macOS Tauri dev builds |
| 230 | |
| 231 | `tauri.conf.json` `minimumSystemVersion` is not enough for `tauri dev`. |
| 232 | |
| 233 | For apps that link Swift-based plugins such as `tauri-plugin-iap`, add `src-tauri/.cargo/config.toml` with: |
| 234 | |
| 235 | - `MACOSX_DEPLOYMENT_TARGET=14.0` |
| 236 | - `-mmacosx-version-min=14.0` for both Apple targets |
| 237 | - host `CC` and `CXX` overrides to `/usr/bin/clang` and `/usr/bin/clang++` |
| 238 | |
| 239 | If you see `libswift_Concurrency.dylib` at runtime, fix Cargo/macOS config first. |
| 240 | |
| 241 | ## Web console conventions |
| 242 | |
| 243 | The admin UI lives in `smbcloud-web-console`. |
| 244 | |
| 245 | Use the `Auth` area, not generic settings pages, for tenant auth app management. |
| 246 | |
| 247 | Expected behavior: |
| 248 | |
| 249 | - scope auth view to selected workspace/project |
| 250 | - if workspace has an auth app, show the app and its users |
| 251 | - if not, allow: |
| 252 | - creating a new auth app |
| 253 | - attaching an existing tenant auth app |
| 254 | - show app id in list views |
| 255 | - hide app secret by default on detail views |
| 256 | - show linked/shared workspaces on detail pages |
| 257 | |
| 258 | ## Typical change flow |
| 259 | |
| 260 | 1. Decide whether the change is platform auth or tenant auth. |
| 261 | 2. Update Rails first. |
| 262 | 3. If OAuth providers are involved, confirm whether the provider is for `AuthUser` or internal `User`. Default tenant/customer providers to `AuthUser`. |
| 263 | 4. Update Rust or WASM SDK endpoints/parsing if the API contract changed. |
| 264 | 5. Update Tauri or browser clients to match. |
| 265 | 6. Update the web console if auth app management changed. |
| 266 | 7. Validate end-to-end. |
| 267 | |
| 268 | ## Validation |
| 269 | |
| 270 | Use the smallest relevant checks. |
| 271 | |
| 272 | ### Rails |
| 273 | |
| 274 | - `bundle exec rails routes | grep 'v1/client\|auth_apps'` |
| 275 | - `ruby -c` on touched controller/model/mailer files |
| 276 | - `bundle exec rails db:migrate` if schema changed |
| 277 | |
| 278 | ### Rust SDK |
| 279 | |
| 280 | - `cargo check -p smbcloud-auth` |
| 281 | - `cargo check -p smbcloud-auth-sdk-wasm` |
| 282 | |
| 283 | ### Tauri apps |
| 284 | |
| 285 | - `cargo check` in `src-tauri` |
| 286 | - `pnpm build` in the app root when frontend changed |
| 287 | |
| 288 | ### Web console |
| 289 | |
| 290 | - `pnpm build` |
| 291 | |
| 292 | ### Browser SDK apps |
| 293 | |
| 294 | - `pnpm build` |
| 295 | - verify login, logout, and session restore in the browser |
| 296 | - if environment override exists, verify both development and production modes |
| 297 | |
| 298 | ## Common mistakes |
| 299 | |
| 300 | - Sending tenant app credentials to `/v1/users` |
| 301 | - Using `OauthApplication` instead of `AuthApp` for tenant login |
| 302 | - Replacing platform client validation with tenant auth app validation |
| 303 | - Implementing Apple or Google for tenant users on platform `User` instead of `AuthUser` |
| 304 | - Returning raw provider tokens as the primary tenant app session |
| 305 | - Treating a browser or native app `app_secret` as confidential |
| 306 | - Auto-confirming `AuthUser` while telling the client to check email |
| 307 | - Building smbCloud `AuthUser` web auth on top of unrelated NextAuth session state |
| 308 | - Forgetting that `tauri dev` ignores `tauri.conf.json` macOS minimum version |