Quick Integration (Any Language)
Integrate SyAuth using standard HTTP requests from any programming language.
Before You Begin
You need these credentials before starting. Get them from the SyAuth Dashboard.
| What You Need | Where to Find It | Example |
|---|---|---|
| Client ID | Dashboard → OAuth Clients → Your App | a1b2c3d4-5678-90ab-cdef-... |
| Redirect URI | You configure this in Dashboard → OAuth Clients → Redirect URIs | http://localhost:3000/callback |
New to SyAuth? Follow these steps first:
- Create a Nexorix account (SyAuth uses Nexorix for authentication)
- Create your first Application to get your
Client ID
How OAuth Authentication Works
Before diving into code, here's what happens when a user logs in:
Step 1: Generate PKCE Codes
What is PKCE? It's a security feature that prevents attackers from intercepting the authorization code. You generate two related values:
code_verifier— A random secret string (keep this safe!)code_challenge— A hashed version of the verifier (sent to SyAuth)
- Python
- Node.js
- Browser JS
- PHP
import secrets
import hashlib
import base64
# Generate a random 32-byte string, base64url encoded
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
# Create SHA256 hash of verifier, then base64url encode
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
# IMPORTANT: Store code_verifier in session - you'll need it in Step 3!
print(f"code_verifier: {code_verifier}")
print(f"code_challenge: {code_challenge}")
// For Node.js, use the crypto module
const crypto = require('crypto');
function base64UrlEncode(buffer) {
return buffer.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Generate random verifier
const codeVerifier = base64UrlEncode(crypto.randomBytes(32));
// Create SHA256 hash of verifier
const codeChallenge = base64UrlEncode(
crypto.createHash('sha256').update(codeVerifier).digest()
);
// IMPORTANT: Store codeVerifier in session - you'll need it in Step 3!
console.log('code_verifier:', codeVerifier);
console.log('code_challenge:', codeChallenge);
async function generatePKCE() {
// Generate random bytes
const array = new Uint8Array(32);
crypto.getRandomValues(array);
// Base64url encode
const codeVerifier = btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
// Create SHA256 hash
const encoder = new TextEncoder();
const data = encoder.encode(codeVerifier);
const hash = await crypto.subtle.digest('SHA-256', data);
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
// IMPORTANT: Store codeVerifier - you'll need it in Step 3!
// In a browser, use sessionStorage:
sessionStorage.setItem('pkce_code_verifier', codeVerifier);
return { codeVerifier, codeChallenge };
}
<?php
// Generate random verifier
$codeVerifier = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
// Create SHA256 hash of verifier
$codeChallenge = rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '=');
// IMPORTANT: Store $codeVerifier in session - you'll need it in Step 3!
$_SESSION['pkce_code_verifier'] = $codeVerifier;
echo "code_verifier: $codeVerifier\n";
echo "code_challenge: $codeChallenge\n";
?>
Store the code_verifier securely! You'll need it in Step 3 to exchange the authorization code for tokens. If you lose it, you'll have to start over.
Step 2: Redirect User to Login
Build the authorization URL and redirect the user's browser to SyAuth:
GET 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
&code_challenge=YOUR_CODE_CHALLENGE
&code_challenge_method=S256
Parameter Reference
| Parameter | Required | Value | Description |
|---|---|---|---|
response_type | ✅ | code | Always use code for the authorization code flow |
client_id | ✅ | Your Client ID | Find this in Dashboard → OAuth Clients → Your App |
redirect_uri | ✅ | Your callback URL | Must exactly match what you configured in Dashboard |
scope | ✅ | openid profile email | Permissions to request (standard OIDC scopes) |
state | ✅ | Random string | Generate a unique value to prevent CSRF attacks. Verify it matches in Step 3 |
code_challenge | ✅ | From Step 1 | The code_challenge you generated |
code_challenge_method | ✅ | S256 | Always use S256 (SHA-256 hashing) |
Example: Building the URL
- Python
- JavaScript
from urllib.parse import urlencode
import secrets
# Your app's configuration
CLIENT_ID = "your-client-id-from-dashboard" # <-- Get from Dashboard
REDIRECT_URI = "http://localhost:3000/callback" # <-- Must match Dashboard config
# Generate state for CSRF protection
state = secrets.token_urlsafe(32)
# Build authorization URL
params = {
'response_type': 'code',
'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI,
'scope': 'openid profile email',
'state': state,
'code_challenge': code_challenge, # From Step 1
'code_challenge_method': 'S256'
}
auth_url = f"https://api.syauth.com/e/v1/oauth/authorize?{urlencode(params)}"
# Store state in session to verify later
session['oauth_state'] = state
# Redirect user to this URL
print(f"Redirect to: {auth_url}")
// Your app's configuration
const CLIENT_ID = 'your-client-id-from-dashboard'; // <-- Get from Dashboard
const REDIRECT_URI = 'http://localhost:3000/callback'; // <-- Must match Dashboard
// Generate state for CSRF protection
const state = crypto.randomUUID();
// Store state to verify later
sessionStorage.setItem('oauth_state', state);
// Build authorization URL
const params = new URLSearchParams({
response_type: 'code',
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
scope: 'openid profile email',
state: state,
code_challenge: codeChallenge, // From Step 1
code_challenge_method: 'S256'
});
const authUrl = `https://api.syauth.com/e/v1/oauth/authorize?${params}`;
// Redirect user
window.location.href = authUrl;
After the user logs in successfully, SyAuth redirects them back to your redirect_uri with an authorization code.
Step 3: Exchange Code for Tokens
When the user is redirected back to your app, the URL will look like:
https://your-app.com/callback?code=AUTHORIZATION_CODE&state=SAME_STATE_YOU_SENT
Before exchanging the code:
- ✅ Verify the
statematches what you stored (prevents CSRF attacks) - ✅ Extract the
codeparameter
Now exchange the code for access tokens:
- curl
- Python
- JavaScript
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=THE_CODE_FROM_CALLBACK" \
-d "client_id=YOUR_CLIENT_ID" \
-d "redirect_uri=YOUR_REDIRECT_URI" \
-d "code_verifier=YOUR_CODE_VERIFIER_FROM_STEP_1"
import requests
# Get these from the callback URL
authorization_code = request.args.get('code')
returned_state = request.args.get('state')
# SECURITY: Verify state matches
if returned_state != session.get('oauth_state'):
raise Exception("Invalid state - possible CSRF attack!")
# Exchange code for tokens
response = requests.post('https://api.syauth.com/e/v1/oauth/token', data={
'grant_type': 'authorization_code',
'code': authorization_code,
'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI,
'code_verifier': session.get('pkce_code_verifier') # From Step 1!
})
tokens = response.json()
access_token = tokens['access_token']
refresh_token = tokens['refresh_token']
print(f"Access Token: {access_token}")
// Parse the callback URL
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const returnedState = urlParams.get('state');
// SECURITY: Verify state matches
if (returnedState !== sessionStorage.getItem('oauth_state')) {
throw new Error("Invalid state - possible CSRF attack!");
}
// Exchange code for tokens
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: code,
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
code_verifier: sessionStorage.getItem('pkce_code_verifier') // From Step 1!
})
});
const tokens = await response.json();
console.log('Access Token:', tokens.access_token);
Token Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
| Field | Description |
|---|---|
access_token | Use this to authenticate API requests. Valid for 1 hour. |
refresh_token | Use this to get a new access token when the current one expires. |
expires_in | Seconds until the access token expires (3600 = 1 hour). |
Store tokens securely! Use HTTP-only cookies or secure server-side storage. Never expose tokens in client-side JavaScript where they can be accessed by malicious scripts.
Step 4: Call APIs with the Access Token
Use the access_token to make authenticated requests:
- curl
- Python
- JavaScript
# Replace with your actual access token from Step 3
curl https://api.syauth.com/e/v1/user/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
response = requests.get(
'https://api.syauth.com/e/v1/user/profile',
headers={'Authorization': f'Bearer {access_token}'}
)
user = response.json()
print(f"Welcome, {user['first_name']} {user['last_name']}!")
print(f"Email: {user['email']}")
const response = await fetch('https://api.syauth.com/e/v1/user/profile', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const user = await response.json();
console.log(`Welcome, ${user.first_name} ${user.last_name}!`);
Example Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"email_verified": true
}
Step 5: Refresh Expired Tokens
Access tokens expire after 1 hour. Use the refresh_token to get a new access token without requiring the user to log in again:
- Python
- JavaScript
response = requests.post('https://api.syauth.com/e/v1/oauth/token', data={
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': CLIENT_ID
})
new_tokens = response.json()
new_access_token = new_tokens['access_token']
# Also update the refresh_token if a new one is provided
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: 'refresh_token',
refresh_token: storedRefreshToken,
client_id: CLIENT_ID
})
});
const newTokens = await response.json();
Troubleshooting
"Invalid redirect_uri" Error
Cause: The redirect_uri in your request doesn't exactly match what's configured in the Dashboard.
Fix:
- Go to Dashboard → OAuth Clients → Your App → Edit Settings → Redirect URIs
- Ensure the URI matches exactly (including
httpvshttps, trailing slashes, etc.)
"Invalid code_verifier" Error
Cause: The code_verifier doesn't match the code_challenge sent during authorization.
Fix:
- Make sure you're using the same
code_verifieryou generated in Step 1 - Check that you stored it in the session and retrieved it correctly
"Invalid or expired code" Error
Cause: Authorization codes expire after 10 minutes and can only be used once.
Fix:
- Complete the token exchange immediately after receiving the callback
- Don't refresh the callback page (this tries to use the code again)
Complete Example
Full Python Flask Example
from flask import Flask, redirect, request, session
import requests
import secrets
import hashlib
import base64
from urllib.parse import urlencode
app = Flask(__name__)
# IMPORTANT: In production, use a secure, random environment variable
app.secret_key = 'your-secret-key'
# Configuration - get these from your SyAuth Dashboard
CLIENT_ID = 'your-client-id'
REDIRECT_URI = 'http://localhost:5000/callback'
@app.route('/login')
def login():
# Step 1: Generate PKCE
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode().rstrip('=')
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).decode().rstrip('=')
# Store verifier for later
session['pkce_verifier'] = code_verifier
# Generate state
state = secrets.token_urlsafe(32)
session['oauth_state'] = state
# Step 2: Redirect to SyAuth
params = {
'response_type': 'code',
'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI,
'scope': 'openid profile email',
'state': state,
'code_challenge': code_challenge,
'code_challenge_method': 'S256'
}
return redirect(f"https://api.syauth.com/e/v1/oauth/authorize?{urlencode(params)}")
@app.route('/callback')
def callback():
# Verify state
if request.args.get('state') != session.get('oauth_state'):
return "Invalid state!", 400
# Step 3: Exchange code for tokens
response = requests.post('https://api.syauth.com/e/v1/oauth/token', data={
'grant_type': 'authorization_code',
'code': request.args.get('code'),
'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI,
'code_verifier': session.get('pkce_verifier')
})
tokens = response.json()
session['access_token'] = tokens['access_token']
return redirect('/profile')
@app.route('/profile')
def profile():
# Step 4: Use access token
response = requests.get(
'https://api.syauth.com/e/v1/user/profile',
headers={'Authorization': f"Bearer {session.get('access_token')}"}
)
user = response.json()
return f"Hello, {user['first_name']}!"
if __name__ == '__main__':
app.run(port=5000)
Next Steps
- Create Your First Application — Set up your OAuth client
- Full Integration Guide — More detailed examples and edge cases
- API Reference — Complete API documentation
- Security Best Practices — Secure your integration