Outcome
Clear the failed-login lockout for one managed user without resetting password, MFA or user activation.
These examples prove local handler behavior with real isolated SQL and explicitly simulated identity/permission dependencies.
Before you start
-
Verify the intended authenticated identity and the current credential-scoped action before preparing input. Self and managed-user security operations have different authority; a session id does not authorize a different user.
-
Use authorized identity and user/session discovery. Recovery security data and session/device identifiers must remain inside the caller-approved workflow.
-
Review the validated plan and intended effect before confirmation. Provider unlink can remove the last linked provider; verify an alternate working sign-in method first. Unlock clears a lockout, not password, MFA or suspended status. Fixture examples authorize no live mutation or external delivery.
Discover the target
topolo whoami --json
topolo apps --json
topolo actions get app_topolo_auth.users.unlock --detail --json
Use the caller subject or a user returned by authorized users discovery. Read user_oauth_providers.list for that exact user before unlinking a returned provider name; providerUserId is an external identity. Unlock requires target-user management authority.
Input fields
| Field | Required | Meaning |
|---|---|---|
userId | Yes | Existing Auth user id from authorized identity or user discovery. Provider links allow self or authorized managed-user access; account unlock requires target-user management authority even for a self request. |
Effects
-
Clears failed-login count and lockout timestamps for one managed identity, creating default security state if absent.
-
Preserves password, MFA, user activation and organization access. Audit failure is nonfatal.
Interpret the response
HTTP 200 successes use raw target success/message/data/timestamp, which CLI/MCP can wrap or project. Record times are epoch seconds; the envelope timestamp is ISO text. Local fixtures use real canonical SQL and target-user authority with simulated token identity and user organization lookup. They prove neither live permissions nor actual sign-in.
data.userId is the affected Auth identity and unlocked acknowledges the lockout update. failed_login_attempts becomes zero and last_failed_login/account_locked_until become null. If no security row exists, the repository creates default security state and updates it; repetition acknowledges an already-cleared state.
Unlock does not reset a password, verify email, disable MFA, reactivate a suspended user, change organization access or revoke sessions/provider consent. A successful acknowledgment does not prove the user can actually sign in. users.get can return security null when security retrieval fails; null is not proof of cleared lockout. Nonfatal audit failure does not change the successful response.
Target-user management authority is required, including when the caller asks to unlock itself. An authenticated ordinary member or an admin outside the target organization is refused with HTTP 401 AUTH_ERROR, so this denial is not by itself evidence that OAuth expired. The unlock handler prefers an access cookie when present; do not mix identities with a Bearer header.
Worked examples
These are complete raw target-handler responses, not CLI/gateway envelopes or live authorization proof. Replace synthetic identifiers using authorized discovery. Save only the reviewed input as payload.json; inspect validation and plan before executing. --confirm assumes the intended operation is approved. Storage read-back and actual sign-in outcomes require separate verification. Provider unlink does not revoke external accounts, consent or existing Auth sessions. Cookies and Bearer tokens must identify the intended principal consistently.
Administrator clears failed-login lockout while preserving MFA and account status
Input · payload.json:
{
"userId": "usr_managed"
}
CLI:
topolo actions validate app_topolo_auth.users.unlock --data @payload.json --json
topolo actions plan app_topolo_auth.users.unlock --data @payload.json --confirm --json
topolo actions call app_topolo_auth.users.unlock --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.users.unlock",
"input": {
"userId": "usr_managed"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "User account unlocked successfully",
"data": {
"userId": "usr_managed",
"unlocked": true
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Repeated unlock acknowledges already-cleared lockout
Input · payload.json:
{
"userId": "usr_managed"
}
CLI:
topolo actions validate app_topolo_auth.users.unlock --data @payload.json --json
topolo actions plan app_topolo_auth.users.unlock --data @payload.json --confirm --json
topolo actions call app_topolo_auth.users.unlock --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.users.unlock",
"input": {
"userId": "usr_managed"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "User account unlocked successfully",
"data": {
"userId": "usr_managed",
"unlocked": true
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Unlock creates default security state if the target had none
Input · payload.json:
{
"userId": "usr_self"
}
CLI:
topolo actions validate app_topolo_auth.users.unlock --data @payload.json --json
topolo actions plan app_topolo_auth.users.unlock --data @payload.json --confirm --json
topolo actions call app_topolo_auth.users.unlock --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.users.unlock",
"input": {
"userId": "usr_self"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "User account unlocked successfully",
"data": {
"userId": "usr_self",
"unlocked": true
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Verify the result
-
Require data.userId to match the reviewed target. Read authorized users.get security information and independently verify lockout is cleared and unrelated identity/MFA/status fields are preserved.
-
Verify actual sign-in as the intended user through the normal flow before claiming access restored; locked, suspended, MFA and password failure states are separate.
Errors and recovery
Ordinary self member cannot perform administrator account unlock
Captured local refusal · HTTP 401:
{
"input": {
"userId": "usr_self"
},
"response": {
"success": false,
"error": {
"message": "Access denied: You can only unlock users in your organization",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Authenticated admin foreign-target denial also returns AUTH_ERROR
Captured local refusal · HTTP 401:
{
"input": {
"userId": "usr_foreign"
},
"response": {
"success": false,
"error": {
"message": "Access denied: You can only unlock users in your organization",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Missing unlock target returns NOT_FOUND
Captured local refusal · HTTP 404:
{
"input": {
"userId": "usr_missing"
},
"response": {
"success": false,
"error": {
"message": "User not found",
"code": "NOT_FOUND",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Anonymous unlock is refused
Captured local refusal · HTTP 401:
{
"input": {
"userId": "usr_self"
},
"response": {
"success": false,
"error": {
"message": "Access token required",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Security storage failure is not a successful unlock
Captured local refusal · HTTP 500:
{
"input": {
"userId": "usr_managed"
},
"response": {
"success": false,
"error": {
"message": "Isolated security SQL failure",
"code": "SERVER_ERROR",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Published recovery guidance
-
state_conflict(HTTP 409): Read the current resource state, reconcile the intended change, and retry only if still valid. -
AUTH_ERROR(HTTP 401): Verify the intended identity and transport. Unlock AUTH_ERROR can mean authenticated target-user authority denial; refresh only a genuinely expired token for the approved context. -
NOT_FOUND(HTTP 404): Refresh authorized user/provider discovery. Repeated unlink reports a missing link; do not create a fictitious link or infer external account deletion. -
SERVER_ERROR(HTTP 500): Preserve the original error, verify the approved authentication and inspect current target state before reviewing any retry. Invalid-token exceptions and repository errors are both possible.
Recovery boundaries
There is no published relock operation to restore previous failed-login counts/timestamps. Investigate the reason for the lockout and approve unlock deliberately. Do not simulate failed logins as an inverse, reset passwords, disable MFA or activate the user automatically.
Discovery and evidence
This record belongs to app_topolo_auth. Local tests prove real canonical provider/security SQL, target-user authorization and handler responses with simulated tokens and identity lookup. They do not prove live permission, alternate sign-in, external-provider token/consent revocation, actual user login, deployment or production completion.