Skip to main content
Connected Apps let external applications (SaaS, integrations, mobile apps) access your Noorle account on your behalf. You remain in control—you can revoke access anytime.

How It Works

User Authorizes App

App Accesses Your Account

App: "I need to list your agents"

  └─ Sends request with access token
     curl -H "Authorization: Bearer eyJ..." \
     https://api.noorle.com/agents

     └─ Noorle verifies token
     └─ Allows access (user approved)
     └─ Returns: Your agents

User Revokes Access

Console → Settings → Connected Apps
├─ MyApp (connected 3/22)
│  ├─ Permissions: read, execute
│  ├─ Last used: Today 2:30 PM
│  └─ [Revoke]

└─ All tokens immediately invalid
   App can't access anymore

Registering an App

If app supports dynamic registration (OpenID Connect), simply connect:
User clicks "Connect Noorle"

  └─ App registers dynamically
     ├─ Sends app details to Noorle
     ├─ Noorle generates client_id, client_secret
     ├─ User authorizes
     └─ App gets access token
No manual registration needed. App self-registers on first use.

Manual Registration

For legacy apps, register in Console:
Console → Developer → OAuth Apps
├─ Create App
│  ├─ App name: "MyAnalytics"
│  ├─ Description: "Analytics integration"
│  ├─ Redirect URI: https://myapp.example.com/callback
│  ├─ Logo URL: https://myapp.example.com/logo.png
│  │
│  └─ Generated credentials:
│     ├─ client_id: "app_abc123xyz"
│     └─ client_secret: "secret_def456uvw"
│        (save securely, don't share)

OAuth Scopes

Request only permissions you need:
Available scopes:
├─ read         (list, view resources)
├─ execute      (run agents, call tools)
├─ manage       (create, update resources)
├─ admin        (full control, delete)
└─ offline_access (get refresh token)
Example: Data Analytics App
Scopes: read offline_access

Why:
├─ read = can view agents, memory, results
├─ NOT execute = can't run agents (just read data)
├─ offline_access = refresh token for background jobs
Example: Bot Management Console
Scopes: read execute manage offline_access

Why:
├─ read = view agents
├─ execute = run agents for user
├─ manage = let user create agents
├─ offline_access = refresh token for 24/7 monitoring

OAuth Flow Details

1. Authorization Request

App sends user to Noorle:
https://auth.noorle.com/oauth/authorize?
  client_id=app_abc123xyz
  &scope=read%20execute%20offline_access
  &redirect_uri=https://app.example.com/callback
  &state=random-string-to-prevent-csrf
  &response_type=code
Parameters:
  • client_id - App identifier
  • scope - Permissions app is requesting
  • redirect_uri - Where to send user after auth
  • state - Random string (app verifies after redirect)
  • response_type - Always “code”

2. Authorization Code

After user approves, Noorle redirects:
https://app.example.com/callback?
  code=AUTH_CODE_123
  &state=random-string-to-prevent-csrf
App verifies:
// Verify state matches (prevents CSRF)
if (request.state !== session.state) {
  throw new Error("State mismatch - possible CSRF");
}

// Exchange code for token

3. Token Exchange

App exchanges code for access token (backend call):
POST https://api.noorle.com/oauth/token

Body:
{
  "grant_type": "authorization_code",
  "code": "AUTH_CODE_123",
  "client_id": "app_abc123xyz",
  "client_secret": "secret_def456uvw"  // backend only!
}

Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600,
  "token_type": "Bearer"
}

4. Access Protected Resources

App now calls Noorle APIs:
curl -H "Authorization: Bearer eyJhbGc..." \
     https://api.noorle.com/agents

Response:
{
  "agents": [
    { "id": "...", "name": "ResearchBot" },
    { "id": "...", "name": "SupportBot" }
  ]
}

Monitoring Connected Apps

View All Connected Apps

Console → Settings → Connected Apps
├─ App1
│  ├─ Status: Active
│  ├─ Scopes: read execute
│  ├─ Connected: March 22, 2024
│  ├─ Last used: March 22, 2:30 PM
│  └─ Actions: [Revoke]

├─ App2
│  ├─ Status: Active
│  ├─ Scopes: read offline_access
│  ├─ Connected: February 15, 2024
│  ├─ Last used: Never
│  └─ Actions: [Revoke]

└─ App3
   ├─ Status: Inactive (pending confirmation)
   └─ Actions: [Approve] [Deny]

Revoke Access

# Via Console (instant)
Console Settings Connected Apps [App Name] [Revoke]

# Via API
DELETE /api/account/oauth-clients/{client_id}/authorization
Immediate effects:
  • All tokens invalidated
  • App cannot make API calls
  • App receives 401 Unauthorized

Refresh Tokens

If app requested offline_access scope, it has refresh token:
Access token expires (1 hour)

  └─ App uses refresh token to get new access token

     └─ No user interaction needed
        App continues working in background
Example: Daily Report Generator
1. User connects app (scope: offline_access)
2. User goes away
3. 11 PM: App wakes up, needs to run report
4. App's access token expired
5. App refreshes using refresh token
6. Generates report (automatic)
7. User wakes up to report in inbox

Security Considerations

1. Verify SSL Certificate

Only connect over HTTPS:
// INSECURE: HTTP redirect
const redirectUri = "http://app.example.com/callback";
// Token could be intercepted

// SECURE: HTTPS redirect
const redirectUri = "https://app.example.com/callback";
// TLS encryption protects token

2. Protect Client Secret

Backend only, never in browser:
// BAD: Client secret in browser
const clientSecret = "secret_def456uvw";
// Anyone can view in network tab

// GOOD: Client secret on backend
// Stored in .env file, Docker secret, etc.
// Never sent to browser

3. Use PKCE (Mobile Apps)

Mobile apps should use PKCE to protect authorization code:
Mobile App

  ├─ Generate random string (code_verifier)

  ├─ Send to Noorle
  │  + code_challenge (hash of code_verifier)

  ├─ Receive authorization code

  └─ Exchange code for token
     + code_verifier (proves app = same as before)
        (Attacker can't intercept and use code)

Common Patterns

Pattern: Analytics Dashboard

App wants to show user’s agents in dashboard.
{
  "app_name": "Analytics Dashboard",
  "scopes": ["read", "offline_access"],
  "flow": "User authorizes once. App periodically fetches agent metrics."
}
User benefits:
  • Can revoke anytime
  • Metrics stay up-to-date
  • No manual data export needed

Pattern: Slack Integration

Slack app wants to create agents in user’s Noorle account.
{
  "app_name": "Slack to Noorle",
  "scopes": ["read", "execute", "manage", "offline_access"],
  "flow": "User authorizes. Slack app creates agents, executes them, reports back."
}
User benefits:
  • Agents are created in their account (they own them)
  • Can modify/delete agents anytime
  • Can revoke Slack access anytime (agents remain)

Troubleshooting

ProblemSolution
”invalid_client”Client ID/secret incorrect. Check registration.
”invalid_scope”Scope not supported. Check available scopes.
”state mismatch”CSRF protection failed. Session may have expired. Try again.
”code expired”Authorization code valid for 10 minutes only. Re-authorize.
”insufficient_scope”Token doesn’t have required permission. Re-authorize with correct scopes.

Best Practices

Request Minimum Scopes

Don’t ask for admin if read is sufficient. Users trust apps that ask for less.

Clear App Description

Tell user exactly what you’ll do. Be specific about scope usage.

Monitor Token Use

Log when app accesses user’s data. Be transparent about usage.

Support Revocation

Handle 401 Unauthorized gracefully. Prompt user to re-authorize if needed.

Next: Learn about Roles and Permissions for access control.