Secure sign in
Find your Cloudex company.
Confirm your password
Google Authenticator
Scan this QR code in Google Authenticator or another TOTP app. First-time enrollment starts automatically after your verified Cloudex password, when enabled for your account. Previous authenticator resets still require administrator recovery.
Enter the six-digit code shown in your authenticator.
My Cloudex account
Authorize external application
Permissions this application is requestingOnly the selected company's authorized scopes can be approved.
Effective API permissions
Permissions currently enabled for your account and company in HUB.
Each integration requests its own OAuth permissions. Your account's available scopes do not automatically grant an application access.
To authorize a new external application, start its “Connect Cloudex” flow. For manual API tests, use the API access tab.
Save your recovery codes now
Each code works once and cannot be shown again. Store them in a password manager or offline.
Cloudex API Testing
Authorize a registered Cloudex test client using your current MFA session. You can then display the successful access_token and refresh_token response for Swagger, Postman, or another developer tool.
Request permissions
Successful OAuth authorization
Tokens are sensitive credentials. They are kept temporarily on this server and only revealed when you explicitly request them.
How to connect Cloudex from another application
Use OAuth Authorization Code + PKCE (S256). Your application does not verify Google Authenticator codes: Cloudex.Auth handles password, MFA, company selection and consent. Your application receives an authorization code and exchanges it for tokens.
- Register your application in HUB. Choose a unique
client_id, permitted scopes, resource and an exact HTTPS redirect URI, such ashttps://your-app.example.com/oauth/callback. Cloudex must approve/register this URI; including it in a request is not enough. - Send the user's browser to
https://my.cloudex.lv/cloudex-api/api/cloudex-auth/oauth/authorizewithresponse_type=code,client_id,redirect_uri,scope, randomstate,code_challenge,code_challenge_method=S256andresource. - Cloudex.Auth verifies password and MFA and asks the user to approve the requested permissions.
- The browser returns to your registered redirect URI (not to your API endpoint) with
?code=...&state=...&iss=.... Verifystateandiss. Keep the original PKCEcode_verifieron your server. - Your application's backend POSTs
application/x-www-form-urlencodedtohttps://my.cloudex.lv/cloudex-api/api/cloudex-auth/oauth/token. Sendgrant_type=authorization_code,client_id,code, the sameredirect_uri, originalcode_verifierandresource. - Use the access token as
Authorization: Bearer ACCESS_TOKEN. Refresh it by postinggrant_type=refresh_token,client_id,refresh_tokenandresourceto the same token endpoint; always replace the old refresh token with the new one.
For Cloudex API Testing, the expected callback for this root-hosted application is https://my.cloudex.app/auth/ai/developer/callback. For your own app, register that application's callback URL in HUB OAuth client configuration. The exact test callback must also be registered/enabled in HUB. An external application uses its own callback in both the authorization request and token exchange. Never substitute the Cloudex.Auth test callback for an external application's callback.
Example successful token response
{
"access_token": "opaque_access_token_example",
"refresh_token": "opaque_refresh_token_example",
"token_type": "Bearer",
"expires_in": 900,
"scope": "trips.read"
}
Minimal JavaScript / Express example
A server-side example is used so the refresh token never needs to be stored in browser JavaScript. Requires Node.js 20+, npm install express express-session and an HTTPS deployment. Replace the client ID and registered callback before use; the sample session store is development-only.
// Cloudex OAuth client — Node.js 20+ and Express (server-side example)
// npm install express express-session
// Put this app behind HTTPS. Register CALLBACK exactly in HUB first.
import express from 'express';
import session from 'express-session';
import { randomBytes, createHash } from 'node:crypto';
const app = express();
app.set('trust proxy', 1); // only behind your trusted HTTPS proxy
app.use(session({
secret: process.env.SESSION_SECRET, // generate a strong random value
resave: false, saveUninitialized: false,
cookie: { httpOnly: true, secure: true, sameSite: 'lax' }
}));
const API = 'https://my.cloudex.lv/cloudex-api';
const RESOURCE = API;
const CLIENT_ID = 'your-registered-client-id';
const CALLBACK = 'https://your-app.example.com/oauth/callback';
const SCOPES = 'trips.read';
const random = () => randomBytes(32).toString('base64url');
// 1. User clicks “Connect Cloudex” in YOUR application.
app.get('/connect-cloudex', (req, res) => {
const state = random();
const verifier = random();
const challenge = createHash('sha256').update(verifier).digest('base64url');
req.session.cloudexPending = { state, verifier };
const url = new URL(API + '/api/cloudex-auth/oauth/authorize');
for (const [key, val] of Object.entries({
response_type: 'code', client_id: CLIENT_ID, redirect_uri: CALLBACK,
scope: SCOPES, state, code_challenge: challenge,
code_challenge_method: 'S256', resource: RESOURCE
})) url.searchParams.set(key, val);
res.redirect(url.toString());
});
// 2. HUB-registered callback receives ?code=...&state=...&iss=...
app.get('/oauth/callback', async (req, res) => {
const pending = req.session.cloudexPending;
delete req.session.cloudexPending; // single use
if (!pending || req.query.state !== pending.state ||
req.query.iss !== API || req.query.error ||
typeof req.query.code !== 'string') {
return res.status(400).send('Cloudex authorization failed');
}
const form = new URLSearchParams({
grant_type: 'authorization_code', client_id: CLIENT_ID,
code: req.query.code, redirect_uri: CALLBACK,
code_verifier: pending.verifier, resource: RESOURCE
});
try {
const response = await fetch(API + '/api/cloudex-auth/oauth/token', {
method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: form
});
if (!response.ok) return res.status(502).send('Token exchange failed');
const tokens = await response.json();
// Sample only: replace express-session MemoryStore with a secure,
// persistent server-side store before production deployment.
req.session.cloudexTokens = tokens;
res.send('Cloudex connected with scopes: ' + tokens.scope);
} catch {
res.status(502).send('Cloudex token service unavailable');
}
});
// 3. API request using the access token; do not accept a browser-supplied VAT.
app.get('/cloudex/trips', async (req, res) => {
const access = req.session.cloudexTokens?.access_token;
if (!access) return res.status(401).send('Connect Cloudex first');
const response = await fetch(API + '/api/cloudex-auth/oauth-business/trips', {
headers: { Authorization: `Bearer ${access}` }
});
res.status(response.status).type(response.headers.get('content-type') || 'application/json')
.send(await response.text());
});
app.listen(3000); // serve publicly only via the trusted HTTPS proxy
Cloudex administration
Master administrators control companies and application callbacks. Appointed company administrators may manage user-level API permissions for their own company.
Reset a user's authenticator
Revokes a user's authenticator, active sessions and recovery codes, and issues a one-day enrollment invitation.
Manage user permission grants
Manage company scope availability
Enable or disable API access for a user
An API disable revokes issued OAuth grants; it does not disable the user's Cloudex.Auth sign-in.
Enable or suspend company OAuth API access
Appoint a company administrator
Approved OAuth applications and callback URLs
Each callback is an exact approved HTTPS redirect URI. Only Cloudex master administrators can register or modify clients.
The ChatGPT callback is pre-staged as a disabled draft. Check the real MCP connection details before enabling it.