OAuth Setup
OAuth Setup
Section titled “OAuth Setup”API v1 uses the OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange) for authentication. Only confidential clients are supported: your server holds a client_secret and presents it at the token endpoint. PKCE is also required: include code_challenge and code_challenge_method=S256 in the authorization URL, and code_verifier in the token exchange.
This page walks through the full flow: registering a client, directing the user to Credal to authorize, exchanging the resulting code for an access token, and calling the API.
1. Register an OAuth client
Section titled “1. Register an OAuth client”Creating an OAuth client requires approval from your organization's admin. To request one, ask your admin to contact support@credal.ai.
After registration you'll receive a client ID and client secret. Keep the client secret secure — treat it like a password.
2. Direct the user to Credal to authorize
Section titled “2. Direct the user to Credal to authorize”First, generate a PKCE pair: a high-entropy random code_verifier and its code_challenge, the SHA-256 hash of the verifier encoded as base64url without padding. See RFC 7636 for the full requirements. Store the verifier server-side, keyed by state — you'll need it in step 3.
Python
Section titled “Python”import base64, hashlib, secrets
code_verifier = secrets.token_urlsafe(64)
code_challenge = (
base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest())
.rstrip(b"=")
.decode()
)TypeScript (Node)
Section titled “TypeScript (Node)”import { createHash, randomBytes } from "crypto";
const codeVerifier = randomBytes(64).toString("base64url");
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");Then send the user to the Credal authorization endpoint. They'll be asked to sign in (if not already) and approve the requested scopes.
https://app.credal.ai/api/oauth/authorize
?response_type=code
&client_id=<your_client_id>
&redirect_uri=<your_redirect_uri>
&scope=api:agent:message:*
&state=<random_value>
&code_challenge=<code_challenge>
&code_challenge_method=S256| Parameter | Description |
|---|---|
response_type |
Always code |
client_id |
Your client ID from step 1 |
redirect_uri |
The URL Credal redirects back to after authorization (must match your registered redirect URI exactly) |
scope |
Space-separated list of scopes. api:agent:message:* lets you send messages to agents. |
state |
A random, unguessable value you generate (e.g. a UUID). Credal echoes it back in the redirect — your callback must verify it matches before exchanging the code, to prevent CSRF attacks. |
code_challenge |
Required. The base64url-encoded SHA-256 hash of your code_verifier. Requests without it are rejected. |
code_challenge_method |
Required. Must be S256. The plain method is not accepted. |
After the user approves, Credal redirects to your redirect_uri with a short-lived authorization code:
https://your-app.com/callback?code=<authorization_code>&state=<random_value>3. Exchange the code for an access token
Section titled “3. Exchange the code for an access token”The authorization code is not an access token. You must exchange it by making a server-side POST request to the token endpoint. Do not skip this step.
The request must include both your client_secret and the code_verifier from step 2. Credal checks each independently, and the exchange fails if either is missing or invalid.
In your callback handler, use the state value from the redirect to retrieve the code_verifier you stored in step 2, and abort if none exists for that state. Each login attempt has its own verifier, so a server handling concurrent logins must resolve it per request. See oauth.net's PKCE overview for background.
curl -X POST https://app.credal.ai/api/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=<authorization_code>" \
-d "client_id=<your_client_id>" \
-d "client_secret=<your_client_secret>" \
-d "redirect_uri=<your_redirect_uri>" \
-d "code_verifier=<code_verifier>"Python
Section titled “Python”import requests
response = requests.post(
"https://app.credal.ai/api/oauth/token",
data={
"grant_type": "authorization_code",
"code": authorization_code,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"redirect_uri": REDIRECT_URI,
"code_verifier": code_verifier,
},
)
tokens = response.json()
access_token = tokens["access_token"]
refresh_token = tokens["refresh_token"]TypeScript
Section titled “TypeScript”const response = await fetch("https://app.credal.ai/api/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: authorizationCode,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code_verifier: codeVerifier,
}),
});
const { access_token, refresh_token } = await response.json();The response contains the tokens you'll use to call the API:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJ..."
}A few things to note:
- The authorization code expires in 10 minutes and is single-use. Exchange it immediately after receiving it.
- The
redirect_urimust match the one used in step 2 exactly. - The
code_verifiermust be the exact value whose SHA-256 hash you sent ascode_challengein step 2.
4. Call the API
Section titled “4. Call the API”Pass the access_token to the Credal SDK:
Python
Section titled “Python”import credal
client = credal.CredalClient(token=access_token)
response = client.agents.send_message(
agent_id="your-agent-id",
conversation=credal.NewConversation(),
message="Hello!",
)TypeScript
Section titled “TypeScript”import { CredalClient } from "@credal/sdk";
const credal = new CredalClient({
token: accessToken,
environment: "https://app.credal.ai/api/v1",
});
const response = await credal.agents.sendMessage({
agentId: "your-agent-id",
conversation: { type: "new" },
message: "Hello!",
});5. Refresh the access token
Section titled “5. Refresh the access token”Access tokens expire after 1 hour. Use the refresh_token to get a new one without sending the user through the browser flow again:
curl -X POST https://app.credal.ai/api/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=<your_refresh_token>" \
-d "client_id=<your_client_id>" \
-d "client_secret=<your_client_secret>"Python
Section titled “Python”response = requests.post(
"https://app.credal.ai/api/oauth/token",
data={
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
},
)
tokens = response.json()
access_token = tokens["access_token"]
refresh_token = tokens.get("refresh_token", refresh_token) # Credal rotates refresh tokens; persist the new valueRefresh tokens are valid for 30 days and are rotated on every use — each refresh response includes a new refresh_token that replaces the old one. Always persist the new value; the previous token is immediately invalidated. If a refresh token expires, the user will need to go through the browser authorization flow again.