Broker API Gateway v2.4 · 100% RFC 6749 & OIDC Compliant

Developer Spoke Integration Guide

Everything engineering teams need to authenticate users across portfolio websites using the centralized identity broker. Eliminate upstream social vendor setup entirely and exchange single-use cryptographically signed tickets in under 5 minutes.

NoctisID Developer Owl Mascot
● Cipher Sentinel — Developer AI Sentinel
Zero Upstream Setup · 60s Atomic Token Exchange
Quick Jump: 1. Prerequisites & Credentials 2. Architecture & Flow Diagram 3. 6-Step Handshake Protocol 4. Gateway Endpoints Reference 5. SDK Code Samples (PHP/Node/Python) 6. In-App Mobile Auth (iOS/Android) 7. Live Diagnostic Sandbox

1. What You Need to Integrate

The centralized broker completely inverts traditional OAuth overhead. Downstream child sites never touch third-party social provider portals.

✓

What You DO Need (From Tenant Portal)

  • Client ID: Public client identifier (e.g. cid_live_example_9918ab) generated in your workspace.
  • Client Secret: Confidential token (e.g. sec_live_9921ab01...) stored strictly in backend server environment variables.
  • Callback URL: Your site's internal consumption endpoint (e.g. https://app.example.com/auth/callback) registered in your domain inventory.
  • Broker Base URL: The root gateway domain: https://noctisid.com.
✕

What You NEVER Need

  • ✕ No Google Cloud Console apps: No OAuth consent screen submissions, verification videos, or domain DNS txt records.
  • ✕ No Apple Developer accounts: No $99/yr developer memberships, private key .p8 certificates, or Services ID configs.
  • ✕ No Meta / Facebook review: No company verification, data protection assessments, or Graph API app reviews.
  • ✕ No individual callback URLs: Upstream social providers only know the central broker root.

2. Architecture & Authentication Flow

NoctisID operates as an Edge Identity Relay. The client browser never sees upstream client secrets, and the spoke site never touches social provider APIs.

NoctisID Cross-Domain OAuth Flow Architecture Diagram
Hub-and-Spoke Identity Topology
Distributed child websites (Left) $\leftrightarrow$ NoctisID Central Broker (Center) $\leftrightarrow$ Upstream Identity Providers (Right)
Open Full Resolution Diagram ↗

3. The 6-Step Cross-Domain Handshake

Standardized authentication sequence ensuring origin isolation, ticket atomic burn, and CSRF protection.

1

User Initiates Login on Spoke Site

Frontend (Browser)

The user clicks "Sign In with Google" on your site (e.g. app.example.com). Your frontend redirects the browser to the broker's authorize endpoint with your client_id, desired provider, and a random cryptographic state nonce.

GET https://noctisid.com/oauth/authorize?client_id=cid_live_example_9918ab&provider=google&redirect_uri=https://app.example.com/auth/callback&state=sec_xyz123
2

Broker Validates Origin & Proxies to Social Provider

Broker Edge

The broker checks that app.example.com is authorized under tenant tnt_example_corp and that the redirect URI matches. The broker signs an encrypted state token and redirects the browser to the social provider (e.g. Google Accounts).

302 Redirect -> https://accounts.google.com/o/oauth2/v2/auth?client_id=71928410294...&redirect_uri=https://noctisid.com/oauth/callback/google
3

User Authorizes on Provider Screen

Identity Provider

The user enters their credentials or selects their account on Google / Apple / Meta. Upon successful login, the provider redirects the user back to the broker's master callback URI.

4

Broker Issues 60-Second Atomic Ticket

Broker Edge

The broker receives the provider's upstream authorization code, exchanges it for user claims (email, name, provider sub), stores the verified profile in Cloudflare KV with a strict 60-second TTL, and generates a random single-use ticket tkt_.... The user is redirected back to your site:

302 Redirect -> https://app.example.com/auth/callback?ticket=tkt_881fa029bb18&state=sec_xyz123
5

Spoke Backend Atomically Exchanges Ticket for Claims

Backend Server-to-Server

Your site's server receives the ticket parameter. Crucially, your backend calls the broker's /oauth/token endpoint server-to-server with your secret key. The broker atomically burns the ticket (preventing replay attacks) and returns verified identity claims.

POST https://noctisid.com/oauth/token Headers: Authorization: Basic Base64(client_id:client_secret) Body: { "ticket": "tkt_881fa029bb18", "grant_type": "ticket_exchange" }
6

Local User Session Established

Spoke Site Backend

Your server creates or retrieves the user record in your local database using the verified email/ID, sets your site's native HTTP-only cookie session (e.g. PHP session, Express cookie), and redirects the user into their account dashboard.

4. Gateway Endpoints Reference

Official HTTP specification for client application integration, token exchange, and discovery.

GET /oauth/authorize
Public Browser Redirect

Entry point for federated authentication. Validates client domain credentials and redirects user to upstream provider.

Query Parameters
ParameterTypeRequiredDescription
client_idStringYesPublic client ID assigned to your spoke site.
providerStringYesTarget identity provider: google, apple, facebook, x, github, microsoft.
redirect_uriURLYesRegistered callback URL on your domain where the ticket is returned.
stateStringYesOpaque anti-CSRF token generated by your application and verified on return.
scopeStringNoOptional permissions (defaults to openid email profile).
POST /oauth/token
Server-to-Server (Client Secret Required)

Atomically exchanges a 60-second single-use ticket for verified user claims. The ticket is immediately invalidated upon receipt.

Request Body (JSON)
{ "client_id": "cid_live_example_9918ab", "client_secret": "sec_live_9921ab01e8a94...", "ticket": "tkt_881fa029bb18", "grant_type": "ticket_exchange" }
Success Response (HTTP 200 OK)
{ "status": "success", "access_token": "uat_live_eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "user": { "sub": "usr_google_10928410294819", "email": "sarah.developer@example.co.uk", "email_verified": true, "name": "Sarah Developer", "provider": "google", "avatar_url": "https://lh3.googleusercontent.com/a/...", "tenant_id": "tnt_example_corp" } }
GET /oauth/userinfo
Bearer Access Token Required

Returns standard OpenID Connect identity claim assertions for an active bearer access token.

curl -H "Authorization: Bearer uat_live_eyJhb..." https://noctisid.com/oauth/userinfo
GET /.well-known/openid-configuration
Public RFC 8414 Discovery

Machine-readable OpenID Connect discovery metadata, issuer URI, endpoints list, and public JWKS signing keys at /.well-known/jwks.json.

5. Multi-Language SDK & Code Samples

Ready-to-use snippets for your backend stack. Copy, paste, and start authenticating in minutes.

Implement this in your theme's functions.php or custom plugin to handle ticket consumption and log the user in via wp_set_current_user():

<?php /** * NoctisID Spoke Callback Consumer for WordPress / PHP */ add_action('init', 'handle_noctisid_callback'); function handle_noctisid_callback() { if (!isset($_GET['ticket']) || empty($_GET['ticket'])) { return; } $ticket = sanitize_text_field($_GET['ticket']); $client_id = get_option('noctisid_client_id'); // e.g. cid_live_example_9918ab $client_secret = get_option('noctisid_client_secret'); // Store securely! $broker_token_url = 'https://noctisid.com/oauth/token'; // 1. Server-to-Server Ticket Exchange (Atomic Burn) $response = wp_remote_post($broker_token_url, [ 'timeout' => 15, 'headers' => ['Content-Type' => 'application/json'], 'body' => json_encode([ 'client_id' => $client_id, 'client_secret' => $client_secret, 'ticket' => $ticket, 'grant_type' => 'ticket_exchange' ]) ]); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { wp_die('Authentication ticket redemption failed. Please try again.'); } $data = json_decode(wp_remote_retrieve_body($response), true); $user_claims = $data['user']; $email = sanitize_email($user_claims['email']); // 2. Locate or Create Local WordPress User $user = get_user_by('email', $email); if (!$user) { $username = sanitize_user(explode('@', $email)[0]); $user_id = wp_create_user($username, wp_generate_password(24), $email); wp_update_user([ 'ID' => $user_id, 'display_name' => sanitize_text_field($user_claims['name']) ]); $user = get_user_by('id', $user_id); } // 3. Set WordPress Session Cookie & Redirect to Dashboard wp_set_current_user($user->ID); wp_set_auth_cookie($user->ID, true); do_action('wp_login', $user->user_login, $user); wp_safe_redirect(home_url('/dashboard')); exit; }

Clean Express route handler with fetch or axios:

const express = require('express'); const app = express(); const BROKER_URL = 'https://noctisid.com'; const CLIENT_ID = process.env.UNIVERSALAUTH_CLIENT_ID; const CLIENT_SECRET = process.env.UNIVERSALAUTH_CLIENT_SECRET; // 1. Initiate Login Redirect app.get('/auth/login/:provider', (req, res) => { const provider = req.params.provider; // e.g. 'google' or 'apple' const state = crypto.randomBytes(16).toString('hex'); req.session.oauth_state = state; const authUrl = `${BROKER_URL}/oauth/authorize?client_id=${CLIENT_ID}&provider=${provider}&redirect_uri=https://yourdomain.com/auth/callback&state=${state}`; res.redirect(authUrl); }); // 2. Consume 60s Single-Use Ticket app.get('/auth/callback', async (req, res) => { const { ticket, state } = req.query; if (state !== req.session.oauth_state) { return res.status(403).send('State nonce mismatch.'); } try { const exchangeRes = await fetch(`${BROKER_URL}/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: CLIENT_ID, client_secret: CLIENT_SECRET, ticket: ticket, grant_type: 'ticket_exchange' }) }); if (!exchangeRes.ok) { return res.status(401).send('Ticket redemption rejected or expired.'); } const { user, access_token } = await exchangeRes.json(); // 3. Establish Local Session req.session.user = user; res.redirect('/portal/dashboard'); } catch (err) { console.error('Handshake failed:', err); res.status(500).send('Internal auth error.'); } });

Asynchronous ticket verification using httpx and FastAPI:

from fastapi import FastAPI, HTTPException, Request from fastapi.responses import RedirectResponse import httpx import os app = FastAPI() BROKER_URL = "https://noctisid.com" CLIENT_ID = os.getenv("UNIVERSALAUTH_CLIENT_ID") CLIENT_SECRET = os.getenv("UNIVERSALAUTH_CLIENT_SECRET") @app.get("/auth/callback") async def auth_callback(ticket: str, state: str, request: Request): # Verify state against session cookie if state != request.session.get("oauth_state"): raise HTTPException(status_code=403, detail="Invalid state token") # Atomic Ticket Redemption async with httpx.AsyncClient() as client: res = await client.post( f"{BROKER_URL}/oauth/token", json={ "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "ticket": ticket, "grant_type": "ticket_exchange" }, timeout=10.0 ) if res.status_code != 200: raise HTTPException(status_code=401, detail="Ticket expired or burned") data = res.json() user_claims = data["user"] # Store authenticated user in session request.session["user"] = user_claims return RedirectResponse(url="/dashboard", status_code=303)

Add this lightweight JavaScript helper to trigger popups or redirect handshakes on web frontends:

<!-- 1. Include NoctisID SDK --> <script src="https://noctisid.com/assets/js/sdk.js" data-client-id="cid_live_example_9918ab"></script> <!-- 2. Trigger Social Handshakes with Custom Buttons --> <button class="btn btn-google" onclick="NoctisID.login('google')"> Sign in with Google </button> <button class="btn btn-apple" onclick="NoctisID.login('apple')"> Sign in with Apple </button> <!-- Optional: Listen for Authentication Events --> <script> window.addEventListener('noctisid:success', (e) => { console.log('User authenticated!', e.detail.user); window.location.reload(); }); </script>

Mobile apps must never embed confidential secrets. Use RFC 7636 PKCE with ASWebAuthenticationSession (iOS) or CustomTabsIntent (Android):

// 1. Swift (iOS) — In-App Authentication with PKCE import AuthenticationServices class AuthManager: NSObject { func startLogin(provider: String) { let codeVerifier = generateRandomString(64) let codeChallenge = sha256Base64Url(codeVerifier) let callbackScheme = "myapp" // Registered Custom URL Scheme let authURL = URL(string: "https://noctisid.com/oauth/authorize?" + "client_id=cid_live_mobile_app77&" + "provider=\(provider)&" + "redirect_uri=myapp://oauth/callback&" + "code_challenge=\(codeChallenge)&" + "code_challenge_method=S256")! let session = ASWebAuthenticationSession(url: authURL, callbackURLScheme: callbackScheme) { callbackURL, error in guard let callbackURL = callbackURL, error == nil else { return } // Extract the 60s single-use ticket let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false) if let ticket = components?.queryItems?.first(where: { $0.name == "ticket" })?.value { self.exchangeTicketWithPKCE(ticket: ticket, verifier: codeVerifier) } } session.presentationContextProvider = self session.start() } }

6. Mobile & In-App Authentication Architecture

Native iOS, Android, React Native, and Flutter app support with zero client secrets in app binaries.

1

In-App Web Browser Flow (RFC 8252 + PKCE)

Standard flow for mobile apps. The app opens ASWebAuthenticationSession (iOS) or Chrome Custom Tabs (Android). Upon login, the broker redirects to your registered deep link (e.g. myapp://oauth/callback?ticket=tkt_...).

  • ✓ Proof Key for Code Exchange (PKCE) prevents code/ticket interception.
  • ✓ Uses system shared cookies for single-sign-on across Safari/Chrome.
  • ✓ 100% compliant with Apple App Store Guideline 4.8.
2

Native OS SDK Token Relay (`POST /oauth/exchange-native`)

For apps utilizing native OS biometric sheets (Face ID for Apple Sign In or Google Play Services Sign In button). The app receives an id_token directly from the OS SDK and relays it to the broker.

  • ✓ Broker verifies JWT signature against official JWKS keys.
  • ✓ Issues unified broker access token and refresh token.
  • ✓ Provides seamless zero-redirect native UX on mobile devices.

7. Live Diagnostic Handshake Sandbox

Simulate a real-world ticket generation and atomic exchange handshake right now in your browser.

Ready. Click "Execute Test Handshake" to test cross-origin ticket issuance and atomic burn...