AUTHGATE INTEGRATION

Gate Admin Webhooks Integration

How AuthGate Works

AuthGate replaces passwords with push-to-approve authentication. Any application in the AXE Technology stack can integrate in under 5 minutes.

Step 1
Your App
POST /auth/start
Step 2
AuthGate
Creates session
Step 3
Phone
Approve / Deny
Step 4
Webhook
POST to your URL
Step 5
Your App
User authenticated

Quick Start — 3 Steps

1. Register a webhook at /wh1 pointing to your app's callback URL

2. Add the auth trigger to your app (see code below)

3. Handle the webhook callback when the user approves/denies

Integration Code

Start Auth Session

JavaScript
// Start an AuthGate session from your app
const AUTHGATE = 'https://authgate.cloud';

async function startAuth(appId, email) {
  const res = await fetch(`${AUTHGATE}/auth/start`, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ app_id: appId, email }),
  });
  return res.json();
  // Returns: { session_id, code, expires_in }
}

Webhook Handler (Express/Fastify)

JavaScript
const crypto = require('crypto');

// Verify AuthGate webhook signature
function verifySignature(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return `sha256=${expected}` === signature;
}

app.post('/api/authgate/callback', (req, res) => {
  const sig = req.headers['x-authgate-signature'];
  if (!verifySignature(JSON.stringify(req.body), sig, WEBHOOK_SECRET)) {
    return res.status(401).json({error: 'Invalid signature'});
  }

  const { event, session_id, email, device_id } = req.body;

  if (event === 'approved') {
    // User authenticated! Create session, set cookie, etc.
    console.log(`Auth approved: ${email} via ${device_id}`);
  } else if (event === 'denied') {
    console.log(`Auth denied: ${email}`);
  }

  res.json({received: true});
});

Start Auth Session

Python
import requests

AUTHGATE = "https://authgate.cloud"

def start_auth(app_id, email):
    r = requests.post(f"{AUTHGATE}/auth/start", json={
        "app_id": app_id,
        "email": email,
    })
    return r.json()
    # Returns: {"session_id": ..., "code": ..., "expires_in": 300}

Webhook Handler (FastAPI)

Python
import hmac, hashlib
from fastapi import FastAPI, Request, HTTPException

WEBHOOK_SECRET = "your-webhook-secret"

app = FastAPI()

def verify_signature(body: bytes, signature: str) -> bool:
    expected = hmac.new(
        WEBHOOK_SECRET.encode(), body, hashlib.sha256
    ).hexdigest()
    return f"sha256={expected}" == signature

@app.post("/api/authgate/callback")
async def authgate_webhook(request: Request):
    body = await request.body()
    sig = request.headers.get("x-authgate-signature", "")

    if not verify_signature(body, sig):
        raise HTTPException(401, "Invalid signature")

    data = await request.json()

    if data["event"] == "approved":
        # User authenticated!
        print(f"Approved: {data['email']} via {data['device_id']}")
    elif data["event"] == "denied":
        print(f"Denied: {data['email']}")

    return {"received": True}

Start Auth Session

Shell
# Start a new auth session
curl -X POST https://authgate.cloud/auth/start \
  -H "Content-Type: application/json" \
  -d '{"app_id": "my-app", "email": "user@example.com"}'

# Check session status
curl https://authgate.cloud/auth/check/SESSION_ID

# Register a webhook
curl -X POST https://authgate.cloud/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{"app_id": "my-app", "url": "https://my-app.com/callback"}'

# Verify a JWT token
curl https://authgate.cloud/auth/verify?token=YOUR_JWT_TOKEN

Drop-in HTML Widget

Add this to any page to get an AuthGate login button. The gate animation runs inline.

HTML
<!-- AuthGate Login Button -->
<div id="authgate-widget"></div>
<script>
(function() {
  const AUTHGATE = 'https://authgate.cloud';
  const APP_ID = 'your-app-id';
  const el = document.getElementById('authgate-widget');

  el.innerHTML = '<button id="ag-btn" style="padding:12px 32px;'
    + 'background:#0a0e14;color:#00e5ff;border:2px solid #00e5ff;'
    + 'border-radius:8px;font-size:16px;font-weight:700;'
    + 'cursor:pointer;letter-spacing:2px">'
    + 'LOGIN WITH AUTHGATE</button>'
    + '<div id="ag-code" style="display:none;text-align:center;'
    + 'margin-top:12px;font-family:monospace;font-size:28px;'
    + 'color:#00e5ff;letter-spacing:6px"></div>';

  document.getElementById('ag-btn').onclick = async () => {
    const r = await fetch(`${AUTHGATE}/auth/start`, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({app_id: APP_ID, email: 'user'}),
    });
    const d = await r.json();
    document.getElementById('ag-code').style.display = 'block';
    document.getElementById('ag-code').textContent = d.code;

    // Poll for approval
    const poll = setInterval(async () => {
      const c = await (await fetch(
        `${AUTHGATE}/auth/check/${d.session_id}`
      )).json();
      if (c.status === 'approved') {
        clearInterval(poll);
        document.getElementById('ag-code').textContent = 'APPROVED';
        document.getElementById('ag-code').style.color = '#00e676';
        // c.token contains the JWT — send to your backend
      } else if (c.status === 'denied' || c.status === 'expired') {
        clearInterval(poll);
        document.getElementById('ag-code').textContent = c.status.toUpperCase();
        document.getElementById('ag-code').style.color = '#ff5252';
      }
    }, 2000);
  };
})();
</script>

Webhook Payload Reference

When an auth event occurs, AuthGate POSTs to your registered webhook URL with these headers and body:

Headers

Headers
Content-Type: application/json
User-Agent: AuthGate/1.0
X-AuthGate-Event: approved
X-AuthGate-Delivery: wh_id-1711036800
X-AuthGate-Signature: sha256=abc123...

Body (approved)

JSON
{
  "event": "approved",
  "session_id": "a1b2c3d4",
  "timestamp": "2026-03-21T12:00:00Z",
  "app_id": "ops-centre",
  "email": "james@axe.onl",
  "ip": "192.168.1.122",
  "device_id": "ag-abc123def456",
  "device_name": "James iPhone",
  "new_device": false
}

Body (denied)

JSON
{
  "event": "denied",
  "session_id": "a1b2c3d4",
  "timestamp": "2026-03-21T12:00:00Z",
  "app_id": "ops-centre",
  "email": "james@axe.onl",
  "ip": "192.168.1.122",
  "device_id": "ag-abc123def456"
}

Signature Verification

Every webhook includes an X-AuthGate-Signature header with an HMAC-SHA256 digest of the raw request body, signed with your webhook secret. Always verify this before trusting the payload.

Live Webhook Tester

Test the full auth flow right here. Start a session, then approve it from /app on your phone.

App ID
Email

AXE Technology Integration Points

Register webhooks for each AXE app that needs authentication:

ops_centre.py
:8084/api/authgate/callback
Hub authentication
axe.observer
/api/authgate/callback
Frontend dashboard auth
AXE Voice
:3777/api/authgate/callback
Voice assistant auth
axe-remote
:8082/api/authgate/callback
Mobile remote auth
MCP Hub
mcp.axe.onl/callback
Tool access gating
AuthGate Admin
Self (internal)
Admin dashboard auth