T0-D Credential Surface Inventory
| Item |
Value |
| Mode |
Server development /home/scola/odoo |
| Scope |
Credential lifecycle / recovery / session security (T0-U07 / DEC-014) |
| Basis |
Implemented code + known surfaces (post T0-D core wiring) |
| Docs read |
development-guide.md, workspace-governance.md, architecture-api.md, T0-D-preflight.md |
Classification legend
| Code |
Meaning |
SUPPORTED_CANONICAL |
Retained V1 customer/admin path; must stay tested |
INTERNAL_OPERATIONAL |
Ops/platform only; not a school credential-recovery product surface |
LEGACY_REMOVE |
Dead/stub UI or obsolete path; remove or stop exposing |
UNSAFE_DISABLE |
Previously unsafe; fixed in T0-D (no shared defaults / no secret logs) |
DUPLICATE_MERGE |
Multiple entry points; merged to one canonical where done |
DECISION_REQUIRED |
Still needs product/security follow-up outside V1 freeze |
NOT_IMPLEMENTED / EXCLUDED |
Absent or explicitly out of V1; must stay absent/denied |
A. Session / login
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
AUTH-LOGIN |
/login Login.vue; SPMB login |
POST /api/auth/login |
anon → user |
Authenticate |
public allowlist |
SUPPORTED_CANONICAL |
Session rotate + active-role bind |
— |
app logs on error |
Payload includes must_change_password |
AUTH-SESSION |
auth bootstrap |
POST /api/auth/session |
anon/authed |
Hydrate session |
public allowlist |
SUPPORTED_CANONICAL |
read-only |
— |
— |
Exposes force-change flags |
AUTH-SESSION-PROBE |
api probe |
POST /api/auth/session-probe |
authed |
Cookie liveness |
auth=user |
SUPPORTED_CANONICAL |
none |
— |
— |
|
AUTH-LOGOUT |
auth.service.logout |
POST /api/auth/logout |
authed |
Logout + clear active role |
public allowlist / auth=user |
SUPPORTED_CANONICAL |
clear_session_active_role + session.logout |
— |
— |
DUPLICATE_MERGE fixed: FE no longer prefers Odoo /auth/logout as primary |
AUTH-SWITCH-ROLE |
RoleSwitcher |
POST /api/auth/switch-role |
authed |
Acting role switch |
authed |
SUPPORTED_CANONICAL (non-password) |
session role update |
— |
warning logs |
Owned by T0-B; listed for adjacency only |
B. Self-service password + force change
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
PWD-CHANGE-SELF |
ChangePassword.vue |
POST /api/auth/change-password |
self |
old→new; clear must_change |
users.profile.view |
SUPPORTED_CANONICAL |
revoke other sessions; keep current sid |
FE toast |
password_change audit |
Min length 8 |
PWD-FORCE-GATE |
App.vue non-dismissible dialog |
flag from login/session |
user with temp/force flag |
Block app until change |
authed |
SUPPORTED_CANONICAL |
none until change |
— |
— |
Driven by scola_must_change_password |
PWD-REGISTER-STUB |
/register Register.vue |
— |
public |
Empty stub |
public |
LEGACY_REMOVE |
n/a |
n/a |
n/a |
Not part of credential V1 |
C. Public forgot / reset
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
PWD-RESET-REQUEST |
/forgot-password ForgotPassword.vue |
POST /api/auth/password-reset/request |
public |
Request reset mail |
public allowlist |
SUPPORTED_CANONICAL |
none |
email if usable address |
password_reset_request (success/noop) |
Anti-enumeration: same success shape for exist / missing / disabled |
PWD-RESET-CONFIRM |
/reset-password ResetPassword.vue |
POST /api/auth/password-reset/confirm |
public |
Consume token + set password |
public allowlist |
SUPPORTED_CANONICAL |
revoke all sessions for target |
— |
password_reset_confirm |
Hash-at-rest token; single-use; TTL; purpose=password_reset |
RECOVERY-TOKEN-SVC |
— |
scola.credential.recovery.token + credential_token.py |
system |
Issue/validate tokens |
system |
SUPPORTED_CANONICAL |
n/a |
n/a |
issue logged without raw token |
Purposes: password_reset, activation, admin_reset |
D. Admin reset / deactivate
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
PWD-ADMIN-RESET |
/admin/users modal; /admin/reset-password |
POST /api/v1/users/<id>/reset-password |
admin with user-mgmt authority |
Force reset |
users.manage / admin check |
SUPPORTED_CANONICAL |
revoke all target sessions |
no plaintext in response (DEC-014 §D: admin-provided ≥8; admin already knows the value) |
admin_reset |
Always scola_must_change_password=True; require password ≥8; no shared default |
USER-DEACTIVATE |
UserList |
DELETE /api/v1/users/<id> |
admin |
Soft-disable |
admin |
SUPPORTED_CANONICAL |
revoke all sessions |
— |
account_deactivate |
Disabled ≠ lockout policy |
USER-ACTIVATE |
UserList |
PUT /api/v1/users/<id>/activate |
admin |
Soft-enable |
admin |
SUPPORTED_CANONICAL |
none |
— |
app log |
Does not invent unlock-after-lockout |
USER-CREATE-ADMIN |
UserFormModal |
POST /api/v1/users |
admin |
Create user + initial password |
admin |
DECISION_REQUIRED |
none |
— |
— |
Prefer random temp + must_change for V1 alignment (follow-up) |
E. Parent / student account generation
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
ACCT-GEN-STUDENTS |
StudentList.vue CSV |
POST /api/v1/admin/accounts/generate-students |
admin |
Bulk student accounts |
admin |
SUPPORTED_CANONICAL |
none |
CSV; email skipped in bulk |
— |
Temp passwords random (secrets); must_change set |
ACCT-GEN-PARENTS |
ParentList.vue |
POST /api/v1/admin/accounts/generate-parents |
admin |
Bulk parent accounts |
admin |
SUPPORTED_CANONICAL |
none |
CSV |
— |
UNSAFE_DISABLE fixed: no shared gbs123/gts123 |
ACCT-RESET-PARENTS |
ParentList.vue |
POST /api/v1/admin/accounts/reset-parent-passwords |
admin |
Re-issue parent temps |
admin |
SUPPORTED_CANONICAL |
(session revoke not yet bulk-wired — follow risk) |
CSV |
— |
Random high-entropy only |
ACCT-FACULTY-AUTO |
— |
op.faculty._auto_create_user |
system/admin |
Auto teacher user |
internal |
UNSAFE_DISABLE fixed + INTERNAL_OPERATIONAL |
none |
— |
info log without password |
Random password; not logged |
F. SPMB OTP (separate from password reset)
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
SPMB-SIGNUP |
/spmb/register |
POST /api/SPMB/account/register |
public |
Applicant signup + password |
public allowlist |
SUPPORTED_CANONICAL |
creates user; login gated |
OTP email |
mail |
Not password-reset token |
SPMB-VERIFY-OTP |
/spmb/verify-email |
POST /api/SPMB/account/verify-email |
public |
Email activation OTP |
public |
SUPPORTED_CANONICAL |
unlock login |
— |
token model |
scola.spmb.email.token |
SPMB-RESEND-OTP |
verify page |
POST /api/SPMB/account/resend-otp |
public |
Resend OTP |
public |
SUPPORTED_CANONICAL |
none |
OTP email |
— |
Distinct channel from password_reset |
| Surface ID |
FE |
BE |
Actor |
Purpose |
Auth |
Classification |
Session effect |
Notify |
Audit |
Notes |
UNIT-CREATE-ADMIN |
Foundation school units |
POST /api/school/units/users/create-admin |
platform_operator / elevated |
Unit admin bootstrap |
elevated |
INTERNAL_OPERATIONAL |
none |
temp in response |
logs |
Uses must_change; not school self-service recovery |
PLAT-SCHOOL-ADMIN-CREATE |
platform service |
POST /api/v1/platform/school-admins/create |
platform_operator |
School admin bootstrap |
elevated |
INTERNAL_OPERATIONAL |
none |
temporary_password JSON |
logs |
|
FOUND-USER-LINK-CREATE |
Foundation HR |
POST /api/v1/foundation/hr/users/link-or-create |
foundation HR |
Link/create + temp |
foundation.users.manage |
SUPPORTED_CANONICAL (foundation domain) |
none |
— |
— |
must_change on create |
FOUND-PWD-RESET-DEAD |
foundationHr.service.resetPassword |
Registry row without controller |
foundation HR (intended) |
Dead route |
registry only |
NOT_IMPLEMENTED / LEGACY_REMOVE |
n/a |
n/a |
n/a |
/api/v1/foundation/hr/users/reset-password — do not resurrect without DEC; use canonical admin reset |
H. Explicitly excluded / not invented
| Surface ID |
Presence |
Classification |
V1 posture |
BREAK-GLASS-CREDENTIAL / customer login-as |
No customer credential break-glass UI/API |
EXCLUDED (EXCLUDED_AND_DENIED) |
Must remain absent/denied on customer surface |
BREAK-GLASS-UNIT-RBAC |
_is_break_glass_admin for school-unit mutate |
INTERNAL_OPERATIONAL |
Not a password-recovery / impersonation product |
IMPERSONATE / LOGIN-AS |
No implemented surface (comment-only elsewhere) |
EXCLUDED |
EXCLUDED_AND_DENIED |
PWD-EXPIRY |
No periodic password expiry policy |
EXCLUDED / NOT_IMPLEMENTED |
Do not invent |
PWD-LOCKOUT / unlock workflow |
No failed-attempt lockout product |
EXCLUDED / NOT_IMPLEMENTED |
Disabled account ≠ lockout; no customer unlock journey |
LOGOUT-ALL dedicated API |
No separate logout-all route |
NOT_IMPLEMENTED |
Revocation is side-effect of reset/change/admin/deactivate via credential_session |
OPS-SCRIPTS-PASSWORD |
provision/onboard/golden seed scripts |
INTERNAL_OPERATIONAL |
Secrets via env; never committed |
I. Audit + ACL
| Surface ID |
Model / service |
ACL |
Classification |
Notes |
CRED-AUDIT-EVENT |
scola.credential.audit.event |
system-only (base.group_system in ir.model.access.csv) |
SUPPORTED_CANONICAL |
Never store passwords/raw tokens; unauthenticated request audits must not become enumeration oracles for normal users |
CRED-TOKEN-ROW |
scola.credential.recovery.token |
system-only |
SUPPORTED_CANONICAL |
Hash only at rest |
J. Classification summary (post-fix)
| Classification |
Surfaces |
| SUPPORTED_CANONICAL |
login, session, probe, logout /api/auth/logout, change-password, force-change gate, public reset request/confirm, admin reset, deactivate(+revoke), activate, student/parent account gen, SPMB OTP trio, recovery token service, credential audit |
| INTERNAL_OPERATIONAL |
platform/unit admin bootstrap; break-glass unit RBAC; ops password scripts |
| LEGACY_REMOVE |
/register stub; foundation dead reset route (registry/FE leftover) |
| UNSAFE_DISABLE (fixed) |
shared GBS/GTS parent temps removed; faculty password plaintext logging removed |
| DUPLICATE_MERGE (fixed) |
FE logout → /api/auth/logout |
| DECISION_REQUIRED |
admin user-create must_change defaults; bulk parent-reset session revoke completeness |
| NOT_IMPLEMENTED / EXCLUDED |
customer break-glass, impersonation, password expiry, lockout/unlock product, dedicated logout-all API |
K. Product exposure map (V1)
| Task |
Canonical FE |
Canonical API |
| Login |
/login |
/api/auth/login |
| Session |
app bootstrap |
/api/auth/session |
| Logout |
auth store |
/api/auth/logout |
| Forced / self change |
ChangePassword.vue |
/api/auth/change-password |
| Forgot password |
/forgot-password |
/api/auth/password-reset/request |
| Reset with token |
/reset-password |
/api/auth/password-reset/confirm |
| Admin reset |
/admin/users / /admin/reset-password |
/api/v1/users/<id>/reset-password |
| Deactivate |
UserList |
DELETE /api/v1/users/<id> |
SPMB OTP remains a separate activation channel and must not be conflated with password-reset tokens.