Skip to main content

Authentication

Tanqory uses JWT (RS256) issued by admin-api. All other services validate the same token.

Login Flow​

POST https://api.tanqory.com/api/v1/auth/login
Content-Type: application/json

{
"email": "[email protected]",
"password": "SecurePass123!"
}

Response (200):

{
"user": { "id": "usr_abc123", "email": "[email protected]", "name": "John Doe" },
"accessToken": "eyJhbGci...",
"refreshToken": "eyJhbGci...",
"expiresIn": 3600
}

SDK:

const result = await tanqory.auth.login('[email protected]', 'SecurePass123!')
// Tokens are stored automatically — all subsequent requests are authenticated

MFA Challenge​

If MFA is enabled, login returns requiresMfa: true instead of tokens.

const result = await tanqory.auth.login('[email protected]', 'password')

if ('requiresMfa' in result) {
// Prompt user for TOTP code
const session = await tanqory.auth.verifyTotpLogin(result.mfaToken, '123456')
// session.accessToken and session.refreshToken now available
}

OAuth / Social Login​

Redirect users to the provider's authorize endpoint, then exchange the code:

GET https://api.tanqory.com/api/v1/auth/social-accounts/connect/google
GET https://api.tanqory.com/api/v1/auth/social-accounts/connect/apple

For mobile apps, exchange a native ID token directly:

const result = await tanqory.auth.nativeLogin('google', googleIdToken)

Token Refresh​

Access tokens expire after 1 hour. Use the refresh token to get a new pair:

POST https://api.tanqory.com/api/v1/auth/refresh

{ "refreshToken": "eyJhbGci..." }

SDK: Token refresh is handled automatically. The SDK intercepts 401 responses, refreshes the token, and retries the request.

Cross-origin Token Exchange (SSO)​

When the access token is issued at one origin (e.g. admin.tanqory.com) but consumed at another (e.g. store.tanqory.com), the refresh-token cookie is scoped to the issuer. Call auth.exchangeToken(accessToken) on the consumer origin to mint a local httpOnly refresh-token cookie so silent refresh works there too:

// In an OAuth/SSO callback page on the consumer origin:
const token = new URLSearchParams(location.hash.slice(1)).get('token')
await tanqory.auth.exchangeToken(token) // POST /api/v1/auth/exchange
// httpOnly refresh_token cookie is now set at this origin

API: POST /api/v1/auth/exchange — auth via Authorization: Bearer <accessToken> (does not require an existing session).

Session Management​

List and revoke active sessions:

const sessions = await tanqory.auth.getSessions()
// [{ id: "sess_1", device: "Chrome / macOS", lastActive: "2026-04-09T..." }]

await tanqory.auth.revokeSession('sess_1') // Revoke one
await tanqory.auth.revokeAllOtherSessions() // Revoke all except current

Using Tokens in Requests​

All authenticated API calls require the Authorization header:

Authorization: Bearer {accessToken}

The SDK handles this automatically after login. For raw HTTP clients:

curl -H "Authorization: Bearer eyJhbGci..." \
https://api.tanqory.com/api/v1/auth/me

Token Architecture​

admin-api (issuer, RS256) ──JWT──▶ store-api, ai-api, builder-api (validators)

The same JWT is valid across all Tanqory services. You do not need separate tokens per service.