Integration from Any Language
SyAuth is a standard OAuth 2.0 / OpenID Connect provider. You can integrate it from any programming language that can make HTTP requests.
Building a Backend Service? If you are building a daemon, CLI, or service that engages with SyAuth directly (without a human user present), check out the Machine-to-Machine Guide.
Prerequisites
- A SyAuth Application created in the Dashboard
- Your
client_idandredirect_uri - Basic understanding of OAuth 2.0
OAuth 2.0 Flow Overview
1. Generate PKCE code_verifier and code_challenge
2. Redirect user to /oauth/authorize
3. User logs in and authorizes
4. SyAuth redirects back with authorization code
5. Exchange code for tokens at /oauth/token
6. Use access_token to call APIs
7. Refresh token when expired
Step 1: Generate PKCE Parameters
PKCE (Proof Key for Code Exchange) is required for security.
Generate code_verifier
Create a random 43-128 character string using URL-safe characters:
- Python
- JavaScript
- C (OpenSSL)
- PHP
import secrets
import base64
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64UrlEncode(array);
}
function base64UrlEncode(buffer) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
void generate_code_verifier(char *output, size_t len) {
unsigned char random_bytes[32];
RAND_bytes(random_bytes, 32);
BIO *bio = BIO_new(BIO_s_mem());
BIO *b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, random_bytes, 32);
BIO_flush(bio);
BUF_MEM *buffer;
BIO_get_mem_ptr(bio, &buffer);
memcpy(output, buffer->data, buffer->length);
output[buffer->length] = '\0';
BIO_free_all(bio);
// Convert to URL-safe base64
for (int i = 0; output[i]; i++) {
if (output[i] == '+') output[i] = '-';
if (output[i] == '/') output[i] = '_';
if (output[i] == '=') output[i] = '\0';
}
}
function generateCodeVerifier() {
$randomBytes = random_bytes(32);
return rtrim(strtr(base64_encode($randomBytes), '+/', '-_'), '=');
}
Generate code_challenge
SHA256 hash of code_verifier, then base64url encode:
- Python
- JavaScript
- C (OpenSSL)
import hashlib
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
return base64UrlEncode(new Uint8Array(hash));
}
#include <openssl/sha.h>
void generate_code_challenge(const char *verifier, char *output) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256((unsigned char*)verifier, strlen(verifier), hash);
BIO *bio = BIO_new(BIO_s_mem());
BIO *b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, hash, SHA256_DIGEST_LENGTH);
BIO_flush(bio);
BUF_MEM *buffer;
BIO_get_mem_ptr(bio, &buffer);
memcpy(output, buffer->data, buffer->length);
output[buffer->length] = '\0';
BIO_free_all(bio);
// Convert to URL-safe
for (int i = 0; output[i]; i++) {
if (output[i] == '+') output[i] = '-';
if (output[i] == '/') output[i] = '_';
if (output[i] == '=') output[i] = '\0';
}
}
Step 2: Redirect to Authorization Endpoint
Build the authorization URL and redirect the user:
https://api.syauth.com/e/v1/oauth/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=openid profile email
&state=RANDOM_STATE_STRING
&code_challenge=CODE_CHALLENGE_HERE
&code_challenge_method=S256
Parameters:
response_type: Alwayscodeclient_id: Your application's client IDredirect_uri: Must match exactly what's configured in Dashboardscope: Space-separated scopes (e.g.,openid profile email)state: Random string to prevent CSRF (verify this matches on callback)code_challenge: Generated in Step 1code_challenge_method: AlwaysS256
Step 3: Handle the Callback
After the user logs in, SyAuth redirects to your redirect_uri with:
https://your-app.com/callback?
code=AUTHORIZATION_CODE
&state=SAME_STATE_YOU_SENT
- Verify
statematches what you sent - Extract the
codeparameter - Exchange it for tokens (Step 4)
Step 4: Exchange Code for Tokens
Make a POST request to the token endpoint:
- curl
- Python
- JavaScript
- C (libcurl)
- PHP
curl -X POST https://api.syauth.com/e/v1/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 "redirect_uri=YOUR_REDIRECT_URI" \
-d "code_verifier=CODE_VERIFIER_FROM_STEP1"
import requests
response = requests.post('https://api.syauth.com/e/v1/oauth/token/', data={
'grant_type': 'authorization_code',
'code': authorization_code,
'client_id': 'YOUR_CLIENT_ID',
'redirect_uri': 'YOUR_REDIRECT_URI',
'code_verifier': code_verifier
})
tokens = response.json()
access_token = tokens['access_token']
refresh_token = tokens['refresh_token']
const response = await fetch('https://api.syauth.com/e/v1/oauth/token/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
client_id: 'YOUR_CLIENT_ID',
redirect_uri: 'YOUR_REDIRECT_URI',
code_verifier: codeVerifier
})
});
const tokens = await response.json();
#include <curl/curl.h>
CURL *curl = curl_easy_init();
if(curl) {
char postfields[1024];
snprintf(postfields, sizeof(postfields),
"grant_type=authorization_code&code=%s&client_id=%s&redirect_uri=%s&code_verifier=%s",
authorization_code, client_id, redirect_uri, code_verifier);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.syauth.com/e/v1/oauth/token/");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
$ch = curl_init('https://api.syauth.com/e/v1/oauth/token/');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'authorization_code',
'code' => $authorizationCode,
'client_id' => 'YOUR_CLIENT_ID',
'redirect_uri' => 'YOUR_REDIRECT_URI',
'code_verifier' => $codeVerifier
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$tokens = json_decode($response, true);
curl_close($ch);
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Step 5: Use Access Token
Include the access token (from the Step 4 response) in API requests:
- curl
- Python
- JavaScript
- C (libcurl)
# Replace ACCESS_TOKEN with the "access_token" value received in Step 4
curl https://api.syauth.com/e/v1/user/profile/ \
-H "Authorization: Bearer ACCESS_TOKEN_HERE"
headers = {'Authorization': f'Bearer {access_token}'}
response = requests.get('https://api.syauth.com/e/v1/user/profile/', headers=headers)
user = response.json()
const response = await fetch('https://api.syauth.com/e/v1/user/profile/', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const user = await response.json();
struct curl_slist *headers = NULL;
char auth_header[512];
snprintf(auth_header, sizeof(auth_header), "Authorization: Bearer %s", access_token);
headers = curl_slist_append(headers, auth_header);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.syauth.com/e/v1/user/profile/");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(curl);
curl_slist_free_all(headers);
Step 6: Refresh Token
When the access token expires (after 1 hour), use the refresh token:
- curl
- Python
curl -X POST https://api.syauth.com/e/v1/oauth/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=REFRESH_TOKEN_HERE" \
-d "client_id=YOUR_CLIENT_ID"
response = requests.post('https://api.syauth.com/e/v1/oauth/token/', data={
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': 'YOUR_CLIENT_ID'
})
new_tokens = response.json()
Complete Example: Python
import requests
import secrets
import hashlib
import base64
from urllib.parse import urlencode
# Step 1: Generate PKCE
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
# Step 2: Build authorization URL
auth_params = {
'response_type': 'code',
'client_id': 'YOUR_CLIENT_ID',
'redirect_uri': 'http://localhost:3000/callback',
'scope': 'openid profile email',
'state': secrets.token_urlsafe(32),
'code_challenge': code_challenge,
'code_challenge_method': 'S256'
}
auth_url = f"https://api.syauth.com/e/v1/oauth/authorize?{urlencode(auth_params)}"
print(f"Visit: {auth_url}")
# Step 3: User logs in and you get the code
authorization_code = input("Enter authorization code: ")
# Step 4: Exchange for tokens
token_response = requests.post('https://api.syauth.com/e/v1/oauth/token/', data={
'grant_type': 'authorization_code',
'code': authorization_code,
'client_id': 'YOUR_CLIENT_ID',
'redirect_uri': 'http://localhost:3000/callback',
'code_verifier': code_verifier
})
tokens = token_response.json()
access_token = tokens['access_token']
# Step 5: Use access token
user_response = requests.get(
'https://api.syauth.com/e/v1/user/profile/',
headers={'Authorization': f'Bearer {access_token}'}
)
print(user_response.json())
Next Steps
- API Reference - Complete API documentation
- Authentication Concepts - Deep dive into OAuth 2.0
- Security Best Practices - Secure your integration
Need Help?
- Check the the OAuth 2.0 endpoints for detailed endpoint documentation
- For convenience, use our SDKs (Next.js, Django)