Managing your trusted devices
Sessions & devicesA user reviews which browsers may skip the new-device challenge, and revokes the ones they no longer recognise. New in Enhancement 4; counterpart to session management (scenario 21).
- GET /v1/me/devices → { id, label, ip, trustedAt, lastSeenAt, expiresAt, isCurrent }
- DELETE /v1/me/devices/{deviceId} → 204, untrust one — the next login there is challenged again (scenario 11)
- DELETE /v1/me/devices → 204, untrust every device EXCEPT the one this session runs on
/v1/me/devicesauthList my trusted devicesisCurrent is derived from the SESSION's device_id (via the sid claim), not from the cookie — the device cookie is scoped to /v1/auth and deliberately never reaches /v1/me. KNOWN LIMITATION: the dev gateway-token minter does not stamp sid, so in a local setup isCurrent reads false on every row. The stored token hash never reaches the wire.
Field guide — what each value means & where it comes from1 field
Authenticated read with no inputs — the caller is resolved entirely from the verified gateway context. Lists the browsers that may skip the new-device challenge. Modelled on GET /v1/me/sessions: one lists where you are signed IN, this lists what is TRUSTED.
sidheaderclaimoptionalgateway-injectedGET https://api.kerja.team/v1/me/devicesResponse guide — what comes back & what each value means7 fields
200 with a { data } array of the caller's live trusted devices — the browsers that may skip the new-device challenge. The stored token_hash NEVER reaches the wire.
data[].idUUIDalwaysdata[].labelstringalwaysdata[].ipstringalwaysdata[].trustedAttimestampalwaysdata[].lastSeenAttimestampalwaysdata[].expiresAttimestampalwaysdata[].isCurrentbooleanalwaystrue— This row is the caller's own browser — DELETE /v1/me/devices (untrust-all) spares it.false— Another browser — or, locally, EVERY row: the dev gateway-token minter does not stamp sid, so isCurrent reads false on all of them until that gap closes.
/v1/me/devices/{deviceId}authUntrust one device204. Appends device_untrusted. Ownership is checked explicitly, so probing another user's device id returns 404 not_found rather than a silent success (BOLA/IDOR) — ownership is never leaked as 403. Untrusting is NOT signing out: the sessions on that device keep running until they expire or are revoked (scenario 21). Revoke both to fully evict a lost laptop.
Field guide — what each value means & where it comes from1 field
Authenticated. Untrusts ONE device — the next login from that browser is challenged again (scenario 11). Returns 204 and appends a device_untrusted audit event. Untrusting is not signing out: sessions on that device keep running until they expire or are revoked (scenario 21).
deviceIdpathUUIDrequiredfrom a responseDELETE https://api.kerja.team/v1/me/devices/{deviceId}Response guide — what comes back & what each value meansno body
204 No Content — an empty body is the whole success shape. Appends a device_untrusted audit event. The next login from that browser is challenged again (scenario 11); any sessions running on it keep going until they expire or are revoked separately.
/v1/me/devicesauthUntrust all except the current device204. When the context carries no sid, or that session has no device_id, “the current one” has no referent and ALL devices are untrusted — the fail-closed reading: revoking too much costs one extra challenge, while keeping an unidentifiable device would defeat the call. Locally that is the behaviour you will see (see the sid limitation above). Note: password CHANGE and RESET already revoke device trust automatically (scenarios 23 / 24) — a forgotten or changed password is a plausible symptom of compromise, so trust earned before it does not survive it.
Field guide — what each value means & where it comes from1 field
Authenticated, no body and no parameters. Untrusts every device EXCEPT the one this session runs on; 204. When the context carries no sid, or that session has no device_id, “the current one” has no referent and ALL devices are untrusted — the fail-closed reading: revoking too much costs one extra challenge, while keeping an unidentifiable device would defeat the call.
sidheaderclaimoptionalgateway-injectedDELETE https://api.kerja.team/v1/me/devicesResponse guide — what comes back & what each value meansno body
204 No Content — an empty body is the whole success shape. Untrusts every device except the one this session runs on; when sid is absent (as it is locally) or that session has no device_id, ALL devices are untrusted, which is the fail-closed reading.