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