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