Skip to main content
Noorle APIs support three authentication methods: API Keys, JWT Bearer tokens, and OAuth device flow.

Authentication Methods

1. API Key (Simplest)

Use X-API-Key header for REST API calls. Generate API Key:
# Via Console: Settings → API Keys → Create
# Via CLI:
noorle api-key generate
# Output: ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6
Usage:
curl -X GET https://api.noorle.com/v1/capabilities \
  -H "X-API-Key: ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6"
Alternative Headers: API keys accept these headers (in order of preference):
  • X-API-Key: ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6
  • API-Key: ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6
  • Authorization: ApiKey ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6
Best for:
  • CLI tools
  • Service-to-service authentication
  • Simple scripts
  • Development/testing
Security:
  • Treat as a password
  • Rotate periodically
  • Revoke when compromised
  • Scope to specific API keys (read-only vs full access)

2. Bearer Token (OAuth)

Use Authorization: Bearer header with JWT token. Get Token (OAuth Device Flow):
# Step 1: Request device code
noorle login

# Output:
# Please visit: https://console.noorle.com/oauth/device/verify
# Code: XYZABC

# Step 2: User approves on console
# Step 3: CLI polls for token

# Token stored in ~/.noorle/token.json
Manual Token Exchange:
# Request device code
curl -X POST https://api.noorle.com/oauth/device/authorize \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "noorle-cli",
    "scope": "api"
  }'

# Response:
# {
#   "device_code": "ABCD1234",
#   "user_code": "WXYZ",
#   "verification_uri": "https://console.noorle.com/oauth/device/verify",
#   "expires_in": 1800
# }

# User approves at verification_uri

# Poll for token
curl -X POST https://api.noorle.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
    "device_code": "ABCD1234",
    "client_id": "noorle-cli"
  }'

# Response:
# {
#   "access_token": "eyJhbGc...",
#   "token_type": "Bearer",
#   "expires_in": 3600
# }
Usage:
curl -X GET https://api.noorle.com/v1/capabilities \
  -H "Authorization: Bearer eyJhbGc..."
Token Refresh:
curl -X POST https://api.noorle.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "refresh_token_value",
    "client_id": "noorle-cli"
  }'

# Response with new access_token
Best for:
  • User-initiated workflows
  • Web applications
  • Mobile apps
  • Delegated access
Token Structure (JWT):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decoded payload:
{
  "sub": "user-id",
  "account_id": "account-id",
  "scope": "api",
  "iat": 1516239022,
  "exp": 1516242622
}

3. Service Account Token

For server-to-server authentication with extended expiry. Create Service Account:
noorle service-account create --name "integration-bot"

# Output:
# Service Account ID: sa_1234567890
# Client ID: noorle-sa-1234567890
# Client Secret: secret_abcdefg

# Store secret securely (shown only once)
Get Token:
curl -X POST https://api.noorle.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "noorle-sa-1234567890",
    "client_secret": "secret_abcdefg",
    "scope": "api"
  }'

# Response:
# {
#   "access_token": "eyJhbGc...",
#   "token_type": "Bearer",
#   "expires_in": 86400
# }
Usage:
curl -X GET https://api.noorle.com/v1/capabilities \
  -H "Authorization: Bearer eyJhbGc..."
Best for:
  • Automation and CI/CD
  • Server-to-server communication
  • Scheduled jobs
  • Long-lived integrations

MCP Gateway Authentication

MCP Gateways require OAuth token or API key. Connect via Bearer Token:
curl -N -H "Authorization: Bearer eyJhbGc..." \
  https://mcp-{gateway-id}.noorle.com/sse \
  --no-buffer --raw
Via Query Parameter (limited security):
curl -N https://mcp-{gateway-id}.noorle.com/sse?access_token=eyJhbGc... \
  --no-buffer --raw

A2A Gateway Authentication

A2A Gateways require OAuth token. WebSocket Connection:
const token = "eyJhbGc...";
const url = `wss://agent-{gateway-id}.noorle.com/ws?token=${token}`;

const ws = new WebSocket(url);
ws.onmessage = (event) => {
  const message = JSON.parse(event.data);
  // Handle message
};
HTTP with Bearer:
curl -X POST https://agent-{gateway-id}.noorle.com/message/send \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello"}'

Token Management

Expiration and Refresh

Tokens expire after set duration:
{
  "access_token": "...",
  "expires_in": 3600,
  "refresh_token": "..."
}
Refresh before expiry:
curl -X POST https://api.noorle.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "refresh_...",
    "client_id": "noorle-cli"
  }'

Token Revocation

Revoke tokens when no longer needed:
noorle token revoke eyJhbGc...

# Or via API
curl -X POST https://api.noorle.com/oauth/token/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGc..."
  }'

Checking Token Status

Validate token before use:
curl -X POST https://api.noorle.com/oauth/introspect \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGc..."
  }'

# Response:
# {
#   "active": true,
#   "scope": "api",
#   "expires_at": 1711123200
# }

Authentication Examples

Python

import requests
from datetime import datetime, timedelta

class NoorleAuth:
    def __init__(self, api_key=None, token=None):
        self.api_key = api_key
        self.token = token
        self.token_expiry = None

    def headers(self):
        if self.api_key:
            return {"X-API-Key": self.api_key}
        elif self.token:
            return {"Authorization": f"Bearer {self.token}"}
        return {}

    def refresh_token(self, client_id, client_secret):
        # Refresh logic
        pass

# Usage
auth = NoorleAuth(api_key="ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6")
resp = requests.get(
    "https://api.noorle.com/v1/capabilities",
    headers=auth.headers()
)

JavaScript/TypeScript

import fetch from "node-fetch";

class NoorleAuth {
  constructor(apiKey?: string, token?: string) {
    this.apiKey = apiKey;
    this.token = token;
  }

  headers() {
    if (this.apiKey) {
      return { "X-API-Key": this.apiKey };
    }
    if (this.token) {
      return { Authorization: `Bearer ${this.token}` };
    }
    return {};
  }
}

// Usage
const auth = new NoorleAuth(
  undefined,
  "eyJhbGc..."
);

const response = await fetch(
  "https://api.noorle.com/v1/capabilities",
  {
    headers: auth.headers(),
  }
);

cURL

# With API Key
curl -H "X-API-Key: ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6" \
  https://api.noorle.com/v1/capabilities

# With Bearer Token
curl -H "Authorization: Bearer eyJhbGc..." \
  https://api.noorle.com/v1/capabilities

# With Device Flow (CLI handles this)
noorle login
noorle api-call GET /v1/capabilities

Security Best Practices

Protect API Keys

  • ❌ Don’t commit to version control
  • ✅ Use .env or secrets management
  • ❌ Don’t hardcode in code
  • ✅ Load from environment
  • ❌ Don’t log or display
  • ✅ Rotate regularly
# .env file
NOORLE_API_KEY=ak-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4s9t0u1v2w3x4y5z6

# Code
import os
api_key = os.getenv("NOORLE_API_KEY")

Token Scope

Use minimal scopes:
# Generate token with specific scope
noorle oauth-token generate \
  --scope "read:plugins" \
  --scope "write:agents"

# Limits what token can do

TLS/HTTPS

Always use HTTPS:
# ✅ Correct
curl https://api.noorle.com/...

# ❌ Never use HTTP
curl http://api.noorle.com/...  # Insecure!

Audit Access

Monitor authentication:
# View login history
noorle audit logs --filter auth

# Revoke compromised tokens
noorle token revoke TOKEN_VALUE

# Check active sessions
noorle session list

Troubleshooting

“Invalid API Key”
  • Check key starts with ak-
  • Verify key hasn’t been revoked
  • Regenerate if unsure
“Token Expired”
  • Refresh using refresh_token
  • Re-authenticate if expired
“Insufficient Permissions”
  • Check token/key scope
  • Ensure account has access
  • Contact admin if needed

Next Steps