sign in as a person
Reach the REST API as a person, with no script key and no password, by having them approve a login in their browser
API
A person is in this loop. Step two blocks until someone logged into the site in a browser opens the page and clicks approve. Nothing in the recipe can do that for them, and a run with nobody at the browser ends with the request forgotten and a 404.
Call
import platform, time, webbrowser
import requests
L = f"{site}/internal_api/app_session_request"
# 1. Ask for a login. No credentials of any kind. appName is what the person sees.
made = requests.post(L, data={"appName": "my tool", "machineId": platform.node()}, timeout=30).json()
sid, url = made["sessionRequestId"], made["url"]
# 2. Put the url in front of the person and poll until they approve. A request nobody approves is
# forgotten after about five minutes and answers 404 from then on, so ask again and show the new
# url rather than keep polling a dead id.
webbrowser.open(url)
while True:
r = requests.put(f"{L}/{sid}", timeout=30)
if r.status_code == 404:
made = requests.post(L, data={"appName": "my tool", "machineId": platform.node()}, timeout=30).json()
sid, url = made["sessionRequestId"], made["url"]
webbrowser.open(url)
continue
d = r.json()
if d.get("approved"):
break
time.sleep(2)
session_token, login = d["sessionToken"], d["userLogin"] # handed out once; keep it now
# 3. Spend it. Same endpoint as a script key, different grant. Repeatable: a session token is not
# consumed by minting, so hold the session token and mint a bearer whenever expires_in runs out.
t = requests.post(f"{site}/api/v1/auth/access_token",
data={"grant_type": "session_token", "session_token": session_token},
headers={"Accept": "application/json"}, timeout=30).json()
headers = {"Authorization": f"Bearer {t['access_token']}", "Accept": "application/json"}
Response
Step two, the one 200 that holds the token:
{"approved": true, "sessionToken": "<token>", "userLogin": "<login>"}
Step three:
{"token_type": "Bearer", "access_token": "<token>", "expires_in": 600, "refresh_token": "<token>"}
The bearer's middle segment, decoded (027_auth_permissions):
{"user": {"type": "HumanUser", "id": 253}, "sudo_as_login": null, "auth_type": "session_token", "session_uuid": null}
Notes
useris aHumanUser, so every row this bearer writes has the person ascreated_byand, on a Version, asuser, which the web UI shows as Artist. A script key gets the same result only throughsudo_as_login, and that needs an administrator to grantcan_impersonate_this_userper person (027_auth_permissions). This needs nobody.- The person's permission level applies, not a script's. Rows collapse to what they may see
(
027_auth_permissions); on the probed site the approver was in theAdminset and saw everything. expires_inis 600, the same as a script token, andgrant_type=refresh_tokenon the returnedrefresh_tokenanswers 200 with another 600. Re-minting from the session token costs the same one call and needs no refresh bookkeeping.- The session token is the credential to keep, not the bearer. How long the site keeps it alive is the
site's
User Session Expirypreference (052_app_session_launcher), and is not returned anywhere. machineIdis not checked when polling, so it is a label for the person, not a binding.