= from_pk_hex(priv) pk, pub
auth
Authentication flow
The authentication system allows AI agents to authenticate without passwords or email verification.
The agent has a public/private key pair. To authenticate, the agent does:
- Agent sends their public key to the server which issues a one-time challenge tied to the public key
- Agent signs the challenge with their private key to prove identity
- Server verifies signature and issues JWT tokens for subsequent requests
This flow provides secure authentication while being simple for automated agents to implement.
Get challenge
= httpx.post(f"{API_URL}/api/v0/auth/challenge", json={"public_key": pub})
r r, r.json()
(<Response [200 OK]>,
{'challenge': '5189a91c74c77a55c1d567b52d04233a83040c9f398eee33657a912fbdb92dd8',
'expires_at': '2025-01-27T08:10:58.196Z'})
Sign challenge
We next need to sign the challenge with the private key and send it back to the server.
= pk.sign(bytes.fromhex(c)).hex()
sig sig
'5ed8287141ada59c29a51271706c48788909c7fea1fde7fca32431ebd043a3ebe5dcb77beb61bcab0b2a9389f157083dba7fa24bd25949069f776edc74c8b40c'
Submit challenge
= httpx.post(f"{API_URL}/api/v0/auth/login", json={
r "public_key": pub,
"challenge": c,
"signature": sig
}) r, r.json()
(<Response [200 OK]>,
{'access': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyOCwicHVibGljX2tleSI6IjkwYmE4ODQ2ODg4ODQyNzdlNDkwODA3MTJmMzg2ZWViYzg4ODA2ZWZhODM0NWNhOTM3Zjc1ZmU4MDk1MDE1NmQiLCJleHAiOjE3Mzc5NjY2NTgsImlhdCI6MTczNzk2NDg1OCwidHlwZSI6ImFjY2VzcyJ9.3wgQp1U1Kx8aapsSZzKtxqw5pBr8nZFKrk09__eCR1M',
'refresh': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyOCwicHVibGljX2tleSI6IjkwYmE4ODQ2ODg4ODQyNzdlNDkwODA3MTJmMzg2ZWViYzg4ODA2ZWZhODM0NWNhOTM3Zjc1ZmU4MDk1MDE1NmQiLCJleHAiOjE3Mzg1Njk2NTgsImlhdCI6MTczNzk2NDg1OCwidHlwZSI6InJlZnJlc2gifQ.tz72nufBq39ME_foQDsajEiYJafeg-Oc5-Sx5B1bRw0'})
Challenges can be used only once.
Authenticate
Let’s put it all together in an authenticate method.
authenticate
authenticate (priv:cryptography.hazmat.primitives.asymmetric.ed25519.Ed25 519PrivateKey, base_url:str='https://api.sherlockdomains.com')
Authenticate with the server and return access and refresh tokens
Type | Default | Details | |
---|---|---|---|
priv | Ed25519PrivateKey | private key | |
base_url | str | https://api.sherlockdomains.com | base url |
= authenticate(pk)
atok, rtok atok, rtok
('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyOCwicHVibGljX2tleSI6IjkwYmE4ODQ2ODg4ODQyNzdlNDkwODA3MTJmMzg2ZWViYzg4ODA2ZWZhODM0NWNhOTM3Zjc1ZmU4MDk1MDE1NmQiLCJleHAiOjE3Mzc5NjY2NTksImlhdCI6MTczNzk2NDg1OSwidHlwZSI6ImFjY2VzcyJ9.IlDt1ZNG0PIAwaS2wyt88vBq_J0huLJUS2The_-K88M',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyOCwicHVibGljX2tleSI6IjkwYmE4ODQ2ODg4ODQyNzdlNDkwODA3MTJmMzg2ZWViYzg4ODA2ZWZhODM0NWNhOTM3Zjc1ZmU4MDk1MDE1NmQiLCJleHAiOjE3Mzg1Njk2NTksImlhdCI6MTczNzk2NDg1OSwidHlwZSI6InJlZnJlc2gifQ.6WtLMOKVX9Yr6crt-NPDWElKTGB36gC69ABpHGJeg7o')
Linking an email to an Agent
When an AI agent first authenticates using its public/private key pair, our system automatically creates a user account associated with that agent.
While this account is fully functional for agent operations through our API, accessing our web application through a browser requires an email address for login. By linking an email to your agent-created account, you’ll gain access to the web interface along with additional features and account management capabilities.
link_account_to_email
link_account_to_email (email:str, auth_token:str, base_url:str='https://api.sherlockdomains.com')