OAuth Verify / Exchange authorization code
/oauth/tokenExchanges code + PKCE verifier for access_token. access_token is also verification_token for /verify/validate.
Publishable client_id or secret Bearer — Publishable: client_id in body. Secret sk_*: Authorization Bearer clientId:clientSecret.
Content-Type: application/json · required
client_idstringRequired for publishable clients when not using secret Bearer auth
codestringrequiredcode_verifierstringrequiredgrant_typestringrequiredEnum: authorization_code
redirect_uristringrequired200 Token issued
access_tokenstringrequiredAlso used as verification_token for POST /verify/validate
expires_inintegerrequiredtoken_typestringrequiredEnum: Bearer
userobjectaccessRolestringnullableemailstringnullablefullNamestringnullableidinteger | stringrequiredisAdminbooleannullablephonestringnullablerolestringnullable400 invalid_request or invalid_grant
errorstringerror_descriptionstringvalidboolean401 invalid_client
errorstringerror_descriptionstringvalidboolean| Error | HTTP | Meaning | Fix |
|---|---|---|---|
invalid_grant | 400 | Bad/used/expired code, redirect mismatch, or PKCE failure | Restart OAuth; ensure redirect_uri and code_verifier match start Diagnose → |
invalid_client | 401 | Unknown or mis-authenticated client | Check client_id / secret Bearer format Diagnose → |
@keyra/typescript-sdk: exchangeAuthorizationCode({...})@keyra/web-sdk: Handled inside verify() / handleRedirectCallback()curl -X POST "https://auth.keyra.ie/oauth/token" \
-H "Content-Type: application/json" \
-d '{"grant_type":"authorization_code","code":"auth_code_xxxxxxxx","client_id":"cp_test_xxxxxxxx","code_verifier":"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk","redirect_uri":"http://localhost:3000/auth/keyra/callback"}'Response
{
"access_token": "oat_xxxxxxxx",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"id": "usr_123",
"phone": "+15551234567",
"fullName": "Ada Lovelace",
"email": "ada@example.com"
}
}