Appearance
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:
| Mode | Use Case | Security Level | Setup Complexity |
|---|---|---|---|
| No Authentication | Development, testing, public tools | None | Simple |
| OAuth 2.1 | Production web apps, user-specific access | High | Moderate |
| API Key | Desktop apps, CLI tools, automation | Medium | Simple |
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 operations2. 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
| Scope | Permission | Required? |
|---|---|---|
mcp | Access MCP tools and resources | Yes |
profile | Read user profile information | Recommended |
Client Types
| Client Type | Has Secret? | PKCE Required? | Example |
|---|---|---|---|
| Public Client | No | Yes (mandatory) | SPA, mobile app |
| Confidential Client | Yes | Recommended | Server-side web app |
API Key Authentication
API keys provide simple authentication for desktop applications, CLI tools, and automation.
Creating API Keys
- Sign in to noorle.com
- Navigate to Settings → API Keys
- Click Generate New Key
- Set permissions and optional expiry
- 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
- Always use HTTPS - Never transmit tokens over unencrypted connections
- Implement PKCE - Required for public clients, recommended for all
- Validate state parameter - Prevent CSRF attacks
- Use short-lived tokens - Access tokens expire in 1 hour by default
- Store tokens securely - Use secure storage appropriate for your platform
- Handle token refresh - Implement automatic refresh before expiration
- Validate redirect URIs - Only use pre-registered redirect URIs
API Key Security
- Environment variables - Never hardcode keys in source code
- Least privilege - Create keys with minimal required permissions
- Regular rotation - Rotate keys every 90 days
- Audit logs - Monitor key usage for suspicious activity
- Separate keys - Use different keys for dev/staging/production
General Security
- Rate limiting - Implement exponential backoff for failed requests
- Error handling - Don't expose sensitive info in error messages
- TLS verification - Always verify SSL certificates
- Token scope - Request only necessary scopes
- Audit trail - Log authentication events for security monitoring
Troubleshooting
Common OAuth Errors
| Error | Cause | Solution |
|---|---|---|
invalid_client | Wrong client ID or secret | Verify credentials |
invalid_grant | Expired or reused auth code | Request new authorization |
invalid_request | Missing required parameter | Check all required fields |
unauthorized_client | Client not authorized | Verify client registration |
access_denied | User denied consent | Handle gracefully |
invalid_scope | Requested scope not allowed | Use 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-serverTest 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/listVerify 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
- Update MCP server configuration to require OAuth
- Register your application for OAuth client credentials
- Update client code to implement OAuth flow
- Test thoroughly in staging environment
- 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:
- Implement OAuth alongside API keys
- Gradually migrate users to OAuth
- Monitor both auth methods
- Deprecate API keys once migration complete
Next Steps
- MCP Gateway - Configure your gateway
- Service Accounts - Set up programmatic access
- API Keys - Manage API keys
- Team Management - Configure team access