Code Examples
This guide provides complete, ready-to-use code examples in JavaScript, C#, and Python. These examples demonstrate the full OAuth2/OIDC flow, user management, and API key usage.
> ⚠️ Important: Your base URL must include /tenant/{tenantId}. Once configured, all endpoints are relative to this base URL:
– OAuth Authority:
{BASE_URL}/v2.0/Auth
– User Management:
{BASE_URL}/api/users
– Group Management:
{BASE_URL}/api/groups
> Example: If your server URL is
https://auth.agglestone.comand tenant ID isabc-123, thenBASE_URL = https://auth.agglestone.com/tenant/abc-123
Table of Contents
JavaScript/TypeScript Examples
Complete OAuth2/OIDC Flow
Using oidc-client-ts Library
import { UserManager, WebStorageStateStore } from 'oidc-client-ts';
// Configuration
const BASE_URL = 'https://auth.agglestone.com/tenant/{tenantId}';
const config = {
authority: `${BASE_URL}/v2.0/Auth`,
client_id: '{tenantId}',
redirect_uri: 'https://yourapp.com/callback',
response_type: 'code',
scope: 'openid profile email',
post_logout_redirect_uri: 'https://yourapp.com',
automaticSilentRenew: true,
userStore: new WebStorageStateStore({ store: window.sessionStorage })
};
const userManager = new UserManager(config);
// Login
export async function login() {
try {
await userManager.signinRedirect();
} catch (error) {
console.error('Login error:', error);
throw error;
}
}
// Handle callback
export async function handleCallback() {
try {
const user = await userManager.signinRedirectCallback();
console.log('User authenticated:', user);
return user;
} catch (error) {
console.error('Callback error:', error);
throw error;
}
}
// Get current user
export async function getCurrentUser() {
try {
const user = await userManager.getUser();
return user;
} catch (error) {
console.error('Get user error:', error);
return null;
}
}
// Logout
export async function logout() {
try {
await userManager.signoutRedirect();
} catch (error) {
console.error('Logout error:', error);
throw error;
}
}
// Make authenticated API call
export async function fetchUsers() {
const user = await getCurrentUser();
if (!user || user.expired) {
await login();
return;
}
const response = await fetch(
`${BASE_URL}/api/users`,
{
headers: {
'Authorization': `Bearer ${user.access_token}`,
'Content-Type': 'application/json'
}
}
);
if (response.status === 401) {
// Token expired, try to renew
await userManager.signinSilent();
return fetchUsers();
}
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
Manual Implementation (Without Library)
// PKCE utilities
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64UrlEncode(array);
}
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return base64UrlEncode(new Uint8Array(digest));
}
function base64UrlEncode(array) {
return btoa(String.fromCharCode(...array))
.replace(/+/g, '-')
.replace(///g, '_')
.replace(/=/g, '');
}
function generateState() {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
return base64UrlEncode(array);
}
// Configuration
const tenantId = 'your-tenant-id';
const BASE_URL = `https://auth.agglestone.com/tenant/${tenantId}`;
const redirectUri = 'https://yourapp.com/callback';
// Initiate login
async function initiateLogin() {
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
const state = generateState();
// Store for later
sessionStorage.setItem('code_verifier', codeVerifier);
sessionStorage.setItem('state', state);
// Build authorization URL
const params = new URLSearchParams({
response_type: 'code',
client_id: config.tenantId,
redirect_uri: config.redirectUri,
scope: 'openid profile email',
state: state,
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});
const authUrl = `${BASE_URL}/v2.0/Auth/authorize?${params}`;
window.location.href = authUrl;
}
// Handle callback
async function handleCallback() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
const error = urlParams.get('error');
if (error) {
throw new Error(`Authorization error: ${error}`);
}
// Validate state
const storedState = sessionStorage.getItem('state');
if (state !== storedState) {
throw new Error('State mismatch - possible CSRF attack');
}
// Get code verifier
const codeVerifier = sessionStorage.getItem('code_verifier');
// Exchange code for tokens
const tokens = await exchangeCodeForTokens(code, codeVerifier);
// Store tokens
sessionStorage.setItem('access_token', tokens.access_token);
sessionStorage.setItem('refresh_token', tokens.refresh_token);
sessionStorage.setItem('id_token', tokens.id_token);
// Clean up
sessionStorage.removeItem('code_verifier');
sessionStorage.removeItem('state');
return tokens;
}
// Exchange code for tokens
async function exchangeCodeForTokens(code, codeVerifier) {
const formData = new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: config.redirectUri,
client_id: config.tenantId,
code_verifier: codeVerifier
});
const response = await fetch(
`${BASE_URL}/v2.0/Auth/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error_description || 'Token exchange failed');
}
return await response.json();
}
// Refresh access token
async function refreshAccessToken() {
const refreshToken = sessionStorage.getItem('refresh_token');
if (!refreshToken) {
throw new Error('No refresh token available');
}
const formData = new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: config.tenantId
});
const response = await fetch(
`${BASE_URL}/v2.0/Auth/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
}
);
if (!response.ok) {
// Refresh token expired, need to login again
sessionStorage.clear();
initiateLogin();
return;
}
const tokens = await response.json();
sessionStorage.setItem('access_token', tokens.access_token);
sessionStorage.setItem('refresh_token', tokens.refresh_token);
sessionStorage.setItem('id_token', tokens.id_token);
return tokens;
}
// Make authenticated API call
async function apiCall(endpoint, options = {}) {
let accessToken = sessionStorage.getItem('access_token');
// Check if token is expired (simplified - you should decode JWT to check exp)
// For now, try the request and refresh if needed
const response = await fetch(
`${BASE_URL}${endpoint}`,
{
...options,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
...options.headers
}
}
);
if (response.status === 401) {
// Token expired, refresh and retry
await refreshAccessToken();
accessToken = sessionStorage.getItem('access_token');
const retryResponse = await fetch(
`${config.baseUrl}/tenant/${config.tenantId}${endpoint}`,
{
...options,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
...options.headers
}
}
);
if (!retryResponse.ok) {
throw new Error(`API error: ${retryResponse.status}`);
}
return await retryResponse.json();
}
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
// Usage examples
async function getUsers() {
return apiCall('/api/users?pageNumber=1&pageSize=20');
}
async function createUser(userData) {
return apiCall('/api/users', {
method: 'POST',
body: JSON.stringify(userData)
});
}
API Key Usage (Server-Side)
// Node.js example
const express = require('express');
const app = express();
const API_KEY = process.env.API_KEY;
const BASE_URL = `https://api.agglestone.com/tenant/${process.env.TENANT_ID}`;
async function apiCallWithKey(endpoint, options = {}) {
const response = await fetch(
`${BASE_URL}${endpoint}`,
{
...options,
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
...options.headers
}
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
}
// Get all users
app.get('/api/users', async (req, res) => {
try {
const users = await apiCallWithKey('/api/Users?pageNumber=1&pageSize=20');
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Create user
app.post('/api/users', async (req, res) => {
try {
const newUser = await apiCallWithKey('/api/Users', {
method: 'POST',
body: JSON.stringify(req.body)
});
res.status(201).json(newUser);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
C# / .NET Examples
Using IdentityModel.OidcClient
using IdentityModel.OidcClient;
using System;
using System.Threading.Tasks;
public class AuthService
{
private readonly OidcClient _oidcClient;
private LoginResult _loginResult;
public AuthService(string baseUrl, string tenantId, string redirectUri)
{
var BASE_URL = $"{baseUrl}/tenant/{tenantId}";
var options = new OidcClientOptions
{
Authority = $"{BASE_URL}/v2.0/Auth",
ClientId = tenantId,
RedirectUri = redirectUri,
Scope = "openid profile email",
ResponseMode = OidcClientOptions.AuthorizeResponseMode.Redirect,
Browser = new SystemBrowser()
};
_oidcClient = new OidcClient(options);
}
public async Task<bool> LoginAsync()
{
try
{
_loginResult = await _oidcClient.LoginAsync();
return !_loginResult.IsError;
}
catch (Exception ex)
{
Console.WriteLine($"Login error: {ex.Message}");
return false;
}
}
public async Task<string> GetAccessTokenAsync()
{
if (_loginResult == null || _loginResult.IsError)
{
throw new InvalidOperationException("Not authenticated");
}
// Check if token is expired
if (_loginResult.AccessTokenExpiration < DateTime.UtcNow.AddMinutes(1))
{
// Refresh token
var refreshResult = await _oidcClient.RefreshTokenAsync(_loginResult.RefreshToken);
if (refreshResult.IsError)
{
throw new Exception($"Token refresh failed: {refreshResult.Error}");
}
_loginResult = refreshResult;
}
return _loginResult.AccessToken;
}
public async Task<HttpResponseMessage> MakeApiCallAsync(string endpoint, HttpMethod method, object body = null)
{
var token = await GetAccessTokenAsync();
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(method, endpoint);
if (body != null)
{
request.Content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(body),
System.Text.Encoding.UTF8,
"application/json"
);
}
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
return response;
}
}
// Usage
var authService = new AuthService(
"https://auth.agglestone.com",
"your-tenant-id",
"https://yourapp.com/callback"
);
if (await authService.LoginAsync())
{
var response = await authService.MakeApiCallAsync(
$"{BASE_URL}/api/users",
HttpMethod.Get
);
var users = await response.Content.ReadFromJsonAsync<UserResponse>();
}
Using HttpClient with Manual Implementation
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
public class OAuth2Client
{
private readonly string _baseUrl;
private readonly string _tenantId;
private readonly string _redirectUri;
private readonly HttpClient _httpClient;
private string _accessToken;
private string _refreshToken;
private DateTime _tokenExpiry;
public OAuth2Client(string baseUrl, string tenantId, string redirectUri)
{
_baseUrl = $"{baseUrl}/tenant/{tenantId}";
_tenantId = tenantId;
_redirectUri = redirectUri;
_httpClient = new HttpClient();
}
public string GetAuthorizationUrl(string state, string codeChallenge)
{
var queryParams = HttpUtility.ParseQueryString(string.Empty);
queryParams.Add("response_type", "code");
queryParams.Add("client_id", _tenantId);
queryParams.Add("redirect_uri", _redirectUri);
queryParams.Add("scope", "openid profile email");
queryParams.Add("state", state);
queryParams.Add("code_challenge", codeChallenge);
queryParams.Add("code_challenge_method", "S256");
return $"{_baseUrl}/v2.0/Auth/authorize?{queryParams}";
}
public async Task<TokenResponse> ExchangeCodeForTokensAsync(string code, string codeVerifier)
{
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", _redirectUri),
new KeyValuePair<string, string>("client_id", _tenantId),
new KeyValuePair<string, string>("code_verifier", codeVerifier)
};
var request = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}/v2.0/Auth/token")
{
Content = new FormUrlEncodedContent(formData)
};
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
_accessToken = tokenResponse.AccessToken;
_refreshToken = tokenResponse.RefreshToken;
_tokenExpiry = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn);
return tokenResponse;
}
public async Task<TokenResponse> RefreshTokenAsync()
{
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", _refreshToken),
new KeyValuePair<string, string>("client_id", _tenantId)
};
var request = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}/v2.0/Auth/token")
{
Content = new FormUrlEncodedContent(formData)
};
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
_accessToken = tokenResponse.AccessToken;
_refreshToken = tokenResponse.RefreshToken;
_tokenExpiry = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn);
return tokenResponse;
}
public async Task<string> GetAccessTokenAsync()
{
if (string.IsNullOrEmpty(_accessToken) || _tokenExpiry < DateTime.UtcNow.AddMinutes(1))
{
await RefreshTokenAsync();
}
return _accessToken;
}
public async Task<T> MakeApiCallAsync<T>(string endpoint, HttpMethod method, object body = null)
{
var token = await GetAccessTokenAsync();
var request = new HttpRequestMessage(method, $"{_baseUrl}{endpoint}");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
if (body != null)
{
request.Content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(body),
Encoding.UTF8,
"application/json"
);
}
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>();
}
}
// Token response model
public class TokenResponse
{
public string AccessToken { get; set; }
public string TokenType { get; set; }
public int ExpiresIn { get; set; }
public string RefreshToken { get; set; }
public string IdToken { get; set; }
public string Scope { get; set; }
}
API Key Usage
using System.Net.Http;
using System.Threading.Tasks;
public class ApiKeyClient
{
private readonly string _baseUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
public ApiKeyClient(string baseUrl, string tenantId, string apiKey)
{
_baseUrl = $"{baseUrl}/tenant/{tenantId}";
_tenantId = tenantId;
_apiKey = apiKey;
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("X-API-Key", _apiKey);
}
public async Task<T> GetAsync<T>(string endpoint)
{
var response = await _httpClient.GetAsync($"{_baseUrl}{endpoint}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>();
}
public async Task<T> PostAsync<T>(string endpoint, object body)
{
var content = new StringContent(
System.Text.Json.JsonSerializer.Serialize(body),
System.Text.Encoding.UTF8,
"application/json"
);
var response = await _httpClient.PostAsync($"{_baseUrl}{endpoint}", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>();
}
}
// Usage
var client = new ApiKeyClient(
"https://auth.agglestone.com",
"your-tenant-id",
"your-api-key"
);
var users = await client.GetAsync<PagedResponse<UserResponse>>("/api/Users?pageNumber=1&pageSize=20");
Python Examples
Using authlib Library
from authlib.integrations.requests_client import OAuth2Session
from authlib.oauth2.rfc7636 import CodeChallenge
import requests
import secrets
import hashlib
import base64
class OAuth2Client:
def __init__(self, base_url, tenant_id, redirect_uri):
self.base_url = f"{base_url}/tenant/{tenant_id}"
self.tenant_id = tenant_id
self.redirect_uri = redirect_uri
self.authorization_endpoint = f"{self.base_url}/v2.0/Auth/authorize"
self.token_endpoint = f"{self.base_url}/v2.0/Auth/token"
self.access_token = None
self.refresh_token = None
def generate_code_verifier(self):
"""Generate PKCE code verifier"""
return base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
def generate_code_challenge(self, verifier):
"""Generate PKCE code challenge"""
challenge = hashlib.sha256(verifier.encode('utf-8')).digest()
return base64.urlsafe_b64encode(challenge).decode('utf-8').rstrip('=')
def get_authorization_url(self):
"""Get authorization URL with PKCE"""
code_verifier = self.generate_code_verifier()
code_challenge = self.generate_code_challenge(code_verifier)
state = secrets.token_urlsafe(16)
# Store for later
self.code_verifier = code_verifier
self.state = state
params = {
'response_type': 'code',
'client_id': self.tenant_id,
'redirect_uri': self.redirect_uri,
'scope': 'openid profile email',
'state': state,
'code_challenge': code_challenge,
'code_challenge_method': 'S256'
}
query_string = '&'.join([f"{k}={v}" for k, v in params.items()])
return f"{self.authorization_endpoint}?{query_string}"
def exchange_code_for_tokens(self, code):
"""Exchange authorization code for tokens"""
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': self.redirect_uri,
'client_id': self.tenant_id,
'code_verifier': self.code_verifier
}
response = requests.post(self.token_endpoint, data=data)
response.raise_for_status()
tokens = response.json()
self.access_token = tokens['access_token']
self.refresh_token = tokens['refresh_token']
return tokens
def refresh_access_token(self):
"""Refresh access token"""
data = {
'grant_type': 'refresh_token',
'refresh_token': self.refresh_token,
'client_id': self.tenant_id
}
response = requests.post(self.token_endpoint, data=data)
response.raise_for_status()
tokens = response.json()
self.access_token = tokens['access_token']
self.refresh_token = tokens['refresh_token']
return tokens
def make_api_call(self, endpoint, method='GET', data=None):
"""Make authenticated API call"""
if not self.access_token:
raise Exception("Not authenticated")
url = f"{self.base_url}{endpoint}"
headers = {
'Authorization': f'Bearer {self.access_token}',
'Content-Type': 'application/json'
}
response = requests.request(method, url, headers=headers, json=data)
if response.status_code == 401:
# Token expired, refresh and retry
self.refresh_access_token()
headers['Authorization'] = f'Bearer {self.access_token}'
response = requests.request(method, url, headers=headers, json=data)
response.raise_for_status()
return response.json()
# Usage
client = OAuth2Client(
"https://auth.agglestone.com",
"your-tenant-id",
"https://yourapp.com/callback"
)
# Get authorization URL
auth_url = client.get_authorization_url()
print(f"Visit: {auth_url}")
# After user authenticates, handle callback
code = input("Enter authorization code: ")
tokens = client.exchange_code_for_tokens(code)
# Make API calls
users = client.make_api_call('/api/users?pageNumber=1&pageSize=20')
print(users)
Using requests-oauthlib
from requests_oauthlib import OAuth2Session
import secrets
class OAuth2Client:
def __init__(self, base_url, tenant_id, redirect_uri):
self.base_url = f"{base_url}/tenant/{tenant_id}"
self.tenant_id = tenant_id
self.redirect_uri = redirect_uri
self.authorization_base_url = f"{self.base_url}/v2.0/Auth/authorize"
self.token_url = f"{self.base_url}/v2.0/Auth/token"
def get_authorization_url(self):
"""Get authorization URL"""
oauth = OAuth2Session(
client_id=self.tenant_id,
redirect_uri=self.redirect_uri,
scope='openid profile email'
)
authorization_url, state = oauth.authorization_url(
self.authorization_base_url,
state=secrets.token_urlsafe(16)
)
self.state = state
return authorization_url
def fetch_token(self, authorization_response):
"""Fetch token from authorization response"""
oauth = OAuth2Session(
client_id=self.tenant_id,
redirect_uri=self.redirect_uri
)
token = oauth.fetch_token(
self.token_url,
authorization_response=authorization_response
)
self.oauth = oauth
return token
def get(self, endpoint):
"""Make GET request"""
url = f"{self.base_url}{endpoint}"
return self.oauth.get(url).json()
def post(self, endpoint, data=None):
"""Make POST request"""
url = f"{self.base_url}{endpoint}"
return self.oauth.post(url, json=data).json()
# Usage
client = OAuth2Client(
"https://auth.agglestone.com",
"your-tenant-id",
"https://yourapp.com/callback"
)
auth_url = client.get_authorization_url()
print(f"Visit: {auth_url}")
# After redirect
authorization_response = input("Enter full redirect URL: ")
token = client.fetch_token(authorization_response)
# Make API calls
users = client.get('/api/Users?pageNumber=1&pageSize=20')
API Key Usage
import requests
import os
class ApiKeyClient:
def __init__(self, base_url, tenant_id, api_key):
self.base_url = base_url
self.tenant_id = tenant_id
self.api_key = api_key
self.headers = {
'X-API-Key': api_key,
'Content-Type': 'application/json'
}
def get(self, endpoint):
"""Make GET request"""
url = f"{self.base_url}{endpoint}"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()
def post(self, endpoint, data=None):
"""Make POST request"""
url = f"{self.base_url}{endpoint}"
response = requests.post(url, headers=self.headers, json=data)
response.raise_for_status()
return response.json()
def put(self, endpoint, data=None):
"""Make PUT request"""
url = f"{self.base_url}{endpoint}"
response = requests.put(url, headers=self.headers, json=data)
response.raise_for_status()
return response.json()
def delete(self, endpoint):
"""Make DELETE request"""
url = f"{self.base_url}{endpoint}"
response = requests.delete(url, headers=self.headers)
response.raise_for_status()
return response.status_code == 204
# Usage
client = ApiKeyClient(
"https://auth.agglestone.com",
"your-tenant-id",
os.getenv('API_KEY')
)
# Get users
users = client.get('/api/Users?pageNumber=1&pageSize=20')
# Create user
new_user = client.post('/api/users', {
'email': 'newuser@example.com',
'displayName': 'New User',
'userType': 'Standard',
'enabled': True,
'password': 'SecurePassword123!'
})
Complete Workflow Examples
JavaScript: Full User Management Workflow
class UserManagementClient {
constructor(baseUrl, tenantId, getAccessToken) {
this.baseUrl = baseUrl;
this.tenantId = tenantId;
this.getAccessToken = getAccessToken;
}
async getUsers(pageNumber = 1, pageSize = 20) {
const token = await this.getAccessToken();
const response = await fetch(
`${this.baseUrl}/api/users?pageNumber=${pageNumber}&pageSize=${pageSize}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
return response.json();
}
async createUser(userData) {
const token = await this.getAccessToken();
const response = await fetch(
`${this.baseUrl}/api/users`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
}
);
return response.json();
}
async updateUser(userId, updates) {
const token = await this.getAccessToken();
const response = await fetch(
`${this.baseUrl}/api/users/${userId}`,
{
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
}
);
return response.json();
}
async deleteUser(userId) {
const token = await this.getAccessToken();
const response = await fetch(
`${this.baseUrl}/api/users/${userId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
}
);
return response.status === 204;
}
}
JavaScript: User Management with API Key (Server-Side)
// Node.js server-side example
class UserManagementClient {
constructor(baseUrl, tenantId, apiKey) {
this.baseUrl = `${baseUrl}/tenant/${tenantId}`;
this.tenantId = tenantId;
this.apiKey = apiKey;
}
async getUsers(pageNumber = 1, pageSize = 20) {
const response = await fetch(
`${this.baseUrl}/api/users?pageNumber=${pageNumber}&pageSize=${pageSize}`,
{
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async createUser(userData) {
const response = await fetch(
`${this.baseUrl}/api/users`,
{
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async updateUser(userId, updates) {
const response = await fetch(
`${this.baseUrl}/api/users/${userId}`,
{
method: 'PUT',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async deleteUser(userId) {
const response = await fetch(
`${this.baseUrl}/api/users/${userId}`,
{
method: 'DELETE',
headers: {
'X-API-Key': this.apiKey
}
}
);
return response.status === 204;
}
}
// Usage
const client = new UserManagementClient(
'https://api.agglestone.com',
process.env.TENANT_ID,
process.env.API_KEY
);
const users = await client.getUsers(1, 20);
const newUser = await client.createUser({
email: 'newuser@example.com',
displayName: 'New User',
userType: 'Standard',
enabled: true
});
C#: User Management with API Key (Server-Side)
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class UserManagementClient
{
private readonly string _baseUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
public UserManagementClient(string baseUrl, string tenantId, string apiKey)
{
_baseUrl = baseUrl;
_tenantId = tenantId;
_apiKey = apiKey;
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("X-API-Key", _apiKey);
}
public async Task<PagedResponse<UserResponse>> GetUsersAsync(int pageNumber = 1, int pageSize = 20)
{
var response = await _httpClient.GetAsync(
$"{_baseUrl}/api/users?pageNumber={pageNumber}&pageSize={pageSize}"
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<PagedResponse<UserResponse>>();
}
public async Task<UserIdResponse> CreateUserAsync(CreateUserRequest userData)
{
var content = new StringContent(
JsonSerializer.Serialize(userData),
Encoding.UTF8,
"application/json"
);
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/users",
content
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<UserIdResponse>();
}
public async Task<UserIdResponse> UpdateUserAsync(string userId, UpdateUserRequest updates)
{
var content = new StringContent(
JsonSerializer.Serialize(updates),
Encoding.UTF8,
"application/json"
);
var response = await _httpClient.PutAsync(
$"{_baseUrl}/api/users/{userId}",
content
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<UserIdResponse>();
}
public async Task<bool> DeleteUserAsync(string userId)
{
var response = await _httpClient.DeleteAsync(
$"{_baseUrl}/tenant/{_tenantId}/api/Users/{userId}"
);
return response.StatusCode == System.Net.HttpStatusCode.NoContent;
}
}
// Usage
var client = new UserManagementClient(
"https://auth.agglestone.com",
Environment.GetEnvironmentVariable("TENANT_ID"),
Environment.GetEnvironmentVariable("API_KEY")
);
var users = await client.GetUsersAsync(1, 20);
var newUser = await client.CreateUserAsync(new CreateUserRequest
{
Email = "newuser@example.com",
DisplayName = "New User",
UserType = "Standard",
Enabled = true
});
Python: User Management with API Key (Server-Side)
import requests
import os
from typing import Dict, List, Optional
class UserManagementClient:
def __init__(self, base_url: str, tenant_id: str, api_key: str):
self.base_url = base_url
self.tenant_id = tenant_id
self.api_key = api_key
self.headers = {
'X-API-Key': api_key,
'Content-Type': 'application/json'
}
def get_users(self, page_number: int = 1, page_size: int = 20) -> Dict:
"""Get paginated list of users"""
url = f"{self.base_url}/api/users"
params = {'pageNumber': page_number, 'pageSize': page_size}
response = requests.get(url, headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def get_user(self, user_id: str) -> Dict:
"""Get user by ID"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Users/{user_id}"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()
def create_user(self, user_data: Dict) -> Dict:
"""Create a new user"""
url = f"{self.base_url}/api/users"
response = requests.post(url, headers=self.headers, json=user_data)
response.raise_for_status()
return response.json()
def update_user(self, user_id: str, updates: Dict) -> Dict:
"""Update an existing user"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Users/{user_id}"
response = requests.put(url, headers=self.headers, json=updates)
response.raise_for_status()
return response.json()
def delete_user(self, user_id: str) -> bool:
"""Delete a user"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Users/{user_id}"
response = requests.delete(url, headers=self.headers)
response.raise_for_status()
return response.status_code == 204
# Usage
client = UserManagementClient(
"https://auth.agglestone.com",
os.getenv('TENANT_ID'),
os.getenv('API_KEY')
)
# Get users
users = client.get_users(page_number=1, page_size=20)
print(f"Total users: {users['totalRecords']}")
# Create user
new_user = client.create_user({
'email': 'newuser@example.com',
'displayName': 'New User',
'userType': 'Standard',
'enabled': True,
'password': 'SecurePassword123!'
})
print(f"Created user: {new_user['userId']}")
# Update user
updated = client.update_user(new_user['userId'], {
'displayName': 'Updated Name'
})
# Delete user
client.delete_user(new_user['userId'])
JavaScript: Group Management with API Key (Server-Side)
// Node.js server-side example
class GroupManagementClient {
constructor(baseUrl, tenantId, apiKey) {
this.baseUrl = `${baseUrl}/tenant/${tenantId}`;
this.tenantId = tenantId;
this.apiKey = apiKey;
}
async getGroups(pageNumber = 1, pageSize = 20) {
const response = await fetch(
`${this.baseUrl}/api/groups?pageNumber=${pageNumber}&pageSize=${pageSize}`,
{
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async getGroup(groupId) {
const response = await fetch(
`${this.baseUrl}/api/groups/${groupId}`,
{
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async createGroup(groupData) {
const response = await fetch(
`${this.baseUrl}/api/groups`,
{
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(groupData)
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async updateGroup(groupId, updates) {
const response = await fetch(
`${this.baseUrl}/api/groups/${groupId}`,
{
method: 'PUT',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async deleteGroup(groupId) {
const response = await fetch(
`${this.baseUrl}/api/groups/${groupId}`,
{
method: 'DELETE',
headers: {
'X-API-Key': this.apiKey
}
}
);
return response.status === 204;
}
}
// Usage
const groupClient = new GroupManagementClient(
'https://api.agglestone.com',
process.env.TENANT_ID,
process.env.API_KEY
);
const groups = await groupClient.getGroups(1, 20);
const newGroup = await groupClient.createGroup({
groupName: 'Developers',
description: 'Development team members'
});
C#: Group Management with API Key (Server-Side)
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class GroupManagementClient
{
private readonly string _baseUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
public GroupManagementClient(string baseUrl, string tenantId, string apiKey)
{
_baseUrl = baseUrl;
_tenantId = tenantId;
_apiKey = apiKey;
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("X-API-Key", _apiKey);
}
public async Task<PagedResponse<GroupResponse>> GetGroupsAsync(int pageNumber = 1, int pageSize = 20)
{
var response = await _httpClient.GetAsync(
$"{_baseUrl}/api/groups?pageNumber={pageNumber}&pageSize={pageSize}"
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<PagedResponse<GroupResponse>>();
}
public async Task<GroupResponse> GetGroupAsync(string groupId)
{
var response = await _httpClient.GetAsync(
$"{_baseUrl}/api/groups/{groupId}"
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<GroupResponse>();
}
public async Task<GroupIdResponse> CreateGroupAsync(CreateGroupRequest groupData)
{
var content = new StringContent(
JsonSerializer.Serialize(groupData),
Encoding.UTF8,
"application/json"
);
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/groups",
content
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<GroupIdResponse>();
}
public async Task<GroupIdResponse> UpdateGroupAsync(string groupId, UpdateGroupRequest updates)
{
var content = new StringContent(
JsonSerializer.Serialize(updates),
Encoding.UTF8,
"application/json"
);
var response = await _httpClient.PutAsync(
$"{_baseUrl}/api/groups/{groupId}",
content
);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<GroupIdResponse>();
}
public async Task<bool> DeleteGroupAsync(string groupId)
{
var response = await _httpClient.DeleteAsync(
$"{_baseUrl}/api/groups/{groupId}"
);
return response.StatusCode == System.Net.HttpStatusCode.NoContent;
}
}
// Usage
var groupClient = new GroupManagementClient(
"https://auth.agglestone.com",
Environment.GetEnvironmentVariable("TENANT_ID"),
Environment.GetEnvironmentVariable("API_KEY")
);
var groups = await groupClient.GetGroupsAsync(1, 20);
var newGroup = await groupClient.CreateGroupAsync(new CreateGroupRequest
{
GroupName = "Developers",
Description = "Development team members"
});
Python: Group Management with API Key (Server-Side)
import requests
import os
from typing import Dict, Optional
class GroupManagementClient:
def __init__(self, base_url: str, tenant_id: str, api_key: str):
self.base_url = base_url
self.tenant_id = tenant_id
self.api_key = api_key
self.headers = {
'X-API-Key': api_key,
'Content-Type': 'application/json'
}
def get_groups(self, page_number: int = 1, page_size: int = 20) -> Dict:
"""Get paginated list of groups"""
url = f"{self.base_url}/api/groups"
params = {'pageNumber': page_number, 'pageSize': page_size}
response = requests.get(url, headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def get_group(self, group_id: str) -> Dict:
"""Get group by ID"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Groups/{group_id}"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()
def create_group(self, group_data: Dict) -> Dict:
"""Create a new group"""
url = f"{self.base_url}/api/groups"
response = requests.post(url, headers=self.headers, json=group_data)
response.raise_for_status()
return response.json()
def update_group(self, group_id: str, updates: Dict) -> Dict:
"""Update an existing group"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Groups/{group_id}"
response = requests.put(url, headers=self.headers, json=updates)
response.raise_for_status()
return response.json()
def delete_group(self, group_id: str) -> bool:
"""Delete a group"""
url = f"{self.base_url}/tenant/{self.tenant_id}/api/Groups/{group_id}"
response = requests.delete(url, headers=self.headers)
response.raise_for_status()
return response.status_code == 204
# Usage
group_client = GroupManagementClient(
"https://auth.agglestone.com",
os.getenv('TENANT_ID'),
os.getenv('API_KEY')
)
# Get groups
groups = group_client.get_groups(page_number=1, page_size=20)
print(f"Total groups: {groups['totalRecords']}")
# Create group
new_group = group_client.create_group({
'groupName': 'Developers',
'description': 'Development team members'
})
print(f"Created group: {new_group['id']}")
# Update group
updated = group_client.update_group(new_group['id'], {
'description': 'Updated description'
})
# Delete group
group_client.delete_group(new_group['id'])
Next Steps
- Review the Integration Guide for detailed workflows
- Check User and Group Management for API details
- Understand API Keys vs JWT Tokens for authentication choices