Skip to content

Authentication

Secure authentication for your AI agents and applications with Noorle MCP Gateways. This guide covers OAuth 2.1, API keys, and service-to-service authentication patterns.

Authentication Overview

Noorle MCP Gateways support multiple authentication modes to fit different use cases:

ModeUse CaseSecurity LevelSetup Complexity
No AuthenticationDevelopment, testing, public toolsNoneSimple
OAuth 2.1Production web apps, user-specific accessHighModerate
API KeyDesktop apps, CLI tools, automationMediumSimple

Quick Decision Guide

Choose your authentication method based on your use case:

  • Building a web application? → Use OAuth 2.1 for secure user authentication
  • Creating a CLI tool or automation? → Use API Keys for simple integration
  • Rapid prototyping? → Start with No Authentication, upgrade later
  • Service-to-service communication? → Use Client Credentials flow

OAuth 2.1 Authentication

OAuth 2.1 provides secure, user-specific access to MCP Gateways with granular permissions and automatic token refresh.

OAuth Flow Overview

The OAuth flow enables users to authorize your application to access their MCP Gateway resources:

Step-by-Step Implementation

1. Register Your Application

Dynamic registration (recommended for development):

javascript
const response = await fetch('https://noorle.com/oauth/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    client_name: 'My AI Assistant',
    redirect_uris: ['https://myapp.com/callback'],
    token_endpoint_auth_method: 'client_secret_post',
    grant_types: ['authorization_code', 'refresh_token'],
    response_types: ['code'],
    scope: 'mcp profile'
  })
});

const { client_id, client_secret } = await response.json();
// Store these securely - you'll need them for all OAuth operations

2. Generate PKCE Challenge

Required for public clients (SPAs, mobile apps):

javascript
function generatePKCE() {
  const verifier = generateRandomString(128);
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest('SHA-256', data);
  const challenge = base64UrlEncode(hash);

  return { verifier, challenge };
}

const pkce = generatePKCE();
sessionStorage.setItem('pkce_verifier', pkce.verifier);

3. Redirect to Authorization

javascript
const params = new URLSearchParams({
  response_type: 'code',
  client_id: CLIENT_ID,
  redirect_uri: 'https://myapp.com/callback',
  scope: 'mcp profile',
  state: generateRandomString(32), // CSRF protection
  code_challenge: pkce.challenge,
  code_challenge_method: 'S256',
  resource: 'https://mcp-{uuid}.noorle.dev'
});

window.location.href = `https://noorle.com/oauth/authorize?${params}`;

4. Handle Callback

javascript
async function handleCallback(code, state) {
  // Verify state matches (CSRF protection)
  if (state !== sessionStorage.getItem('oauth_state')) {
    throw new Error('Invalid state');
  }

  // Exchange code for tokens
  const response = await fetch('https://noorle.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      grant_type: 'authorization_code',
      code: code,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      redirect_uri: 'https://myapp.com/callback',
      code_verifier: sessionStorage.getItem('pkce_verifier')
    })
  });

  const tokens = await response.json();
  return tokens;
}

5. Use Access Token

javascript
const response = await fetch('https://mcp-{uuid}.noorle.dev/tools/list', {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  }
});

6. Refresh Tokens

javascript
async function refreshAccessToken(refreshToken) {
  const response = await fetch('https://noorle.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET
    })
  });

  const tokens = await response.json();
  return tokens.access_token;
}

OAuth Scopes

ScopePermissionRequired?
mcpAccess MCP tools and resourcesYes
profileRead user profile informationRecommended

Client Types

Client TypeHas Secret?PKCE Required?Example
Public ClientNoYes (mandatory)SPA, mobile app
Confidential ClientYesRecommendedServer-side web app

API Key Authentication

API keys provide simple authentication for desktop applications, CLI tools, and automation.

Creating API Keys

  1. Sign in to noorle.com
  2. Navigate to SettingsAPI Keys
  3. Click Generate New Key
  4. Set permissions and optional expiry
  5. Copy the key immediately - it won't be shown again

Using API Keys

bash
# HTTP headers
curl -H "Authorization: Bearer noorle_key_abc123..." \
     https://mcp-{uuid}.noorle.dev/tools/list

# Environment variables
export NOORLE_API_KEY="noorle_key_abc123..."

# Application code
const response = await fetch('https://mcp-{uuid}.noorle.dev/tools/call', {
  headers: {
    'Authorization': `Bearer ${process.env.NOORLE_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'web_search',
    arguments: { query: 'AI news' }
  })
});

API Key Best Practices

DO:

  • Store keys in environment variables or secure vaults
  • Use different keys for different environments
  • Rotate keys regularly (every 90 days)
  • Set expiration dates for temporary access
  • Use restricted scopes when possible

DON'T:

  • Commit keys to version control
  • Share keys between applications
  • Embed keys in client-side code
  • Log or display keys in output

Service-to-Service Authentication

For backend services and automation, use the Client Credentials grant:

python
import requests
from datetime import datetime, timedelta

class NoorleServiceClient:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.token = None
        self.token_expires = None

    def get_token(self):
        """Get or refresh service token"""
        if self.token and self.token_expires > datetime.now():
            return self.token

        response = requests.post(
            'https://noorle.com/oauth/token',
            json={
                'grant_type': 'client_credentials',
                'client_id': self.client_id,
                'client_secret': self.client_secret,
                'scope': 'mcp'
            }
        )

        data = response.json()
        self.token = data['access_token']
        self.token_expires = datetime.now() + timedelta(seconds=data['expires_in'])

        return self.token

    def call_tool(self, mcp_server, tool_name, arguments):
        """Call an MCP tool"""
        token = self.get_token()

        response = requests.post(
            f'https://mcp-{mcp_server}.noorle.dev/tools/call',
            headers={'Authorization': f'Bearer {token}'},
            json={'name': tool_name, 'arguments': arguments}
        )

        return response.json()

Platform Integration

Claude Desktop

Add to your Claude Desktop config:

json
{
  "mcpServers": {
    "noorle-gateway": {
      "command": "npx",
      "args": ["@noorle/mcp-client", "https://mcp-{uuid}.noorle.dev"],
      "env": {
        "NOORLE_API_KEY": "noorle_key_..."
      }
    }
  }
}

Config file locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Python Applications

python
from noorle import McpGateway

# OAuth for user context
gateway = McpGateway.from_oauth(
    client_id="...",
    client_secret="...",
    redirect_uri="http://localhost:8080/callback"
)

# API key for automation
gateway = McpGateway.from_api_key(
    api_key=os.environ['NOORLE_API_KEY']
)

# Use tools
result = await gateway.call_tool("web_search", query="AI trends 2025")

Node.js/TypeScript

typescript
import { NoorleMcpClient } from '@noorle/mcp-sdk';

// Initialize with OAuth
const client = new NoorleMcpClient({
  auth: {
    type: 'oauth',
    clientId: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    redirectUri: 'https://myapp.com/callback'
  }
});

// Initialize with API key
const client = new NoorleMcpClient({
  auth: {
    type: 'api_key',
    key: process.env.NOORLE_API_KEY
  }
});

// Discover and use tools
const tools = await client.listTools();
const result = await client.callTool('calculate', { expression: '2 + 2' });

Security Best Practices

OAuth Implementation

  1. Always use HTTPS - Never transmit tokens over unencrypted connections
  2. Implement PKCE - Required for public clients, recommended for all
  3. Validate state parameter - Prevent CSRF attacks
  4. Use short-lived tokens - Access tokens expire in 1 hour by default
  5. Store tokens securely - Use secure storage appropriate for your platform
  6. Handle token refresh - Implement automatic refresh before expiration
  7. Validate redirect URIs - Only use pre-registered redirect URIs

API Key Security

  1. Environment variables - Never hardcode keys in source code
  2. Least privilege - Create keys with minimal required permissions
  3. Regular rotation - Rotate keys every 90 days
  4. Audit logs - Monitor key usage for suspicious activity
  5. Separate keys - Use different keys for dev/staging/production

General Security

  1. Rate limiting - Implement exponential backoff for failed requests
  2. Error handling - Don't expose sensitive info in error messages
  3. TLS verification - Always verify SSL certificates
  4. Token scope - Request only necessary scopes
  5. Audit trail - Log authentication events for security monitoring

Troubleshooting

Common OAuth Errors

ErrorCauseSolution
invalid_clientWrong client ID or secretVerify credentials
invalid_grantExpired or reused auth codeRequest new authorization
invalid_requestMissing required parameterCheck all required fields
unauthorized_clientClient not authorizedVerify client registration
access_deniedUser denied consentHandle gracefully
invalid_scopeRequested scope not allowedUse supported scopes

Debugging Authentication

Check Discovery Endpoints

bash
# Check if auth is required
curl https://mcp-{uuid}.noorle.dev/.well-known/oauth-protected-resource

# Get auth server metadata
curl https://noorle.com/.well-known/oauth-authorization-server

Test with cURL

bash
# Test with API key
curl -H "Authorization: Bearer noorle_key_..." \
     https://mcp-{uuid}.noorle.dev/tools/list

# Test OAuth token
curl -H "Authorization: Bearer eyJ..." \
     https://mcp-{uuid}.noorle.dev/tools/list

Verify Token Format

javascript
// Decode JWT token (for debugging only!)
function debugToken(token) {
  const parts = token.split('.');
  const payload = JSON.parse(atob(parts[1]));
  console.log('Token claims:', payload);
  console.log('Expires:', new Date(payload.exp * 1000));
  console.log('Audience:', payload.aud);
}

Migration Guide

Moving from No Auth to OAuth

  1. Update MCP server configuration to require OAuth
  2. Register your application for OAuth client credentials
  3. Update client code to implement OAuth flow
  4. Test thoroughly in staging environment
  5. Coordinate rollout with users for smooth transition

Moving from API Keys to OAuth

Benefits of migrating:

  • User-specific permissions
  • Automatic token refresh
  • Better audit trail
  • Revocable consent

Migration steps:

  1. Implement OAuth alongside API keys
  2. Gradually migrate users to OAuth
  3. Monitor both auth methods
  4. Deprecate API keys once migration complete

Next Steps