Skip to content

target_session_token PoP (same-device merge)

A PoP credential for merging without OTP when both logi account sessions are active in the same user-agent. The cross-device case uses OTP.

Flow

  1. Issue a token from the Target (B) session → the raw string is shown once (5-minute TTL).
  2. The same browser frontend passes the token to the Requester (A) session (postMessage / sessionStorage / etc. — your choice).
  3. The Requester (A) submits target_session_token to /me/merge → it's consumed atomically as single-use.
  4. Audit: identity_links.merged_via = "session_token".

API

Issue a token

http
POST /api/v1/me/merge/session-token
Authorization: <target session cookie or PAK>
Content-Type: application/json

{ "idempotency_key": "uuid-optional" }

Response (200):

json
{
  "session_token": "ltgt_8f3a...c91",
  "expires_at": "2026-05-11T13:25:00Z"
}
  • The plaintext token is shown once in the response. The server stores only the SHA-256 hash.
  • TTL: issuance time + 5 minutes.
  • Calling the endpoint again with the same idempotency_key returns the same unused token.

Use the token (merge)

http
POST /api/v1/me/merge
Authorization: <requester session cookie or PAK>
Content-Type: application/json

# Option A — cross-device OTP
{ "target_user_id": 42, "otp_code": "123456" }

# Option B — same-device session_token
{ "target_session_token": "ltgt_8f3a...c91" }

Response (200):

json
{
  "ok": true,
  "identity_link_id": 1287,
  "primary_user_id": 17,
  "linked_user_id": 42,
  "merged_via": "session_token"
}

Error codes

StatusCodeMeaning
422conflicting_credentialsBoth otp_code and target_session_token were sent
422missing_credentialsBoth are empty
422self_merge_forbiddenThe token's target user_id == the requester's user_id
401token_expiredThe 5-minute TTL was exceeded
401token_consumedThe token was already used
401invalid_tokenHash mismatch or nonexistent

Security model

ItemBehavior
StorageOnly the SHA-256 hash is stored in merge_session_tokens.token_digest
Single-useconsumed_at is set atomically; a second attempt returns token_consumed
TTLIssuance + 5 minutes
Target bindingThe token is bound to the issuing session's user_id
Self-merge blockIf requester == target, returns 422 self_merge_forbidden
Auditidentity_links.merged_via = "session_token"

OTP vs session_token

OTPsession_token
When to usecross-devicesame-device
PoP mediuma 6-digit code to a verified emailthe target session cookie + a hash token
TTL10 minutes5 minutes
Reusediscarded after one useatomic single-use

Issuing with a PAK (server-to-server / CI/CD)

Requirements

  • The PAK holds the account:merge scope.
  • Specify via: "pak" in the request body (the scope alone does not auto-promote).
  • issued_via = "pak" is recorded on the token record and in the audit log.

curl

bash
curl -X POST https://api.1pass.dev/api/v1/me/merge/session-token \
  -H "Authorization: Bearer logi_pak_xxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" \
  -H "Content-Type: application/json" \
  -d '{"via":"pak","idempotency_key":"ci-merge-2026-05-11-001"}'

Errors

  • via=pak without the scope → 403 insufficient_scope ({"error":"insufficient_scope","required":"account:merge"}).
  • An unknown via value → 400 invalid_via.
  • If an account:merge PAK is lost, revoke it immediately.

Limitations

  • iframe / cross-origin: the target session cookie may not be sent due to the SameSite policy → issue/pass within the same top-level origin, or fall back to OTP.
  • When the cross-device intent is clear, OTP is recommended.

Next steps

Identity가 제품의 신뢰를 만듭니다.