External app events track OAuth 2.0 authorization flows when external applications request access to MCP proxies. These events record user decisions during login and consent screens, providing visibility into which applications users authorize and the scopes they grant.
Event Flow
External app authorization follows a two-step OAuth flow:
Login : User authenticates and confirms identity for the external application
Consent : User reviews and grants (or denies) requested permissions
Each step generates a view event (when the screen loads) and either an approve or reject event (based on user action).
Target Structure
All external app events include three targets to provide complete authorization context:
external_app : The third-party application requesting access
mcp_proxy : The MCP proxy being authorized
project : The project containing the proxy
This multi-target structure allows filtering audit logs by any resource in the authorization chain.
external_app.login_view
Records when a user views the login authorization screen for an external application.
Triggered When
User is redirected to /external-apps/login with a valid login challenge from the external application’s OAuth flow.
Event Schema
External application’s OAuth client ID
External application’s display name
External application’s display name
External application’s OAuth client ID
MCP proxy’s unique identifier
Project’s unique identifier
Organization’s unique identifier
Project’s unique identifier
Organization’s unique identifier
Always /external-apps/login
metadata.user_has_access_to_proxy
Whether the user has permission to access the requested MCP proxy based on project membership and proxy access scope
Example Event
{
"action" : "external_app.login_view" ,
"occurredAt" : "2025-01-15T10:30:00.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/login" ,
"user_has_access_to_proxy" : true
}
}
The user_has_access_to_proxy field indicates whether authorization can proceed. Users without access see a generic error message without revealing why access was denied.
external_app.login_approve
Records when a user approves login for an external application.
Triggered When
User clicks the “Continue” button on the login authorization screen, confirming their identity for the external application.
Event Schema
external_app.login_approve
Same structure as external_app.login_view: external_app, mcp_proxy, and project targets
Always /external-apps/login
Example Event
{
"action" : "external_app.login_approve" ,
"occurredAt" : "2025-01-15T10:31:00.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/login"
}
}
external_app.login_reject
Records when a user rejects login for an external application.
Triggered When
User clicks the “Cancel” button on the login authorization screen, denying their identity confirmation for the external application.
Event Schema
external_app.login_reject
Same structure as external_app.login_view: external_app, mcp_proxy, and project targets
Always /external-apps/login
Example Event
{
"action" : "external_app.login_reject" ,
"occurredAt" : "2025-01-15T10:31:30.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/login"
}
}
external_app.consent_view
Records when a user views the consent authorization screen for an external application.
Triggered When
User is redirected to /external-apps/consent with a valid consent challenge after successful login, showing the requested OAuth scopes.
Event Schema
external_app.consent_view
Same structure as external_app.login_view: external_app, mcp_proxy, and project targets
Always /external-apps/consent
metadata.user_has_access_to_proxy
Whether the user has permission to access the requested MCP proxy
metadata.requested_scopes
Comma-separated list of OAuth scopes requested by the external application (e.g., "openid, profile, email")
Example Event
{
"action" : "external_app.consent_view" ,
"occurredAt" : "2025-01-15T10:31:15.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/consent" ,
"user_has_access_to_proxy" : true ,
"requested_scopes" : "openid, profile, email"
}
}
external_app.consent_approve
Records when a user approves consent and grants permissions to an external application.
Triggered When
User clicks the “Allow” button on the consent screen, granting the requested OAuth scopes to the external application.
Event Schema
external_app.consent_approve
Same structure as external_app.login_view: external_app, mcp_proxy, and project targets
Always /external-apps/consent
Comma-separated list of OAuth scopes actually granted to the application. This is the intersection of requested scopes and scopes the user had permission to grant.
Example Event
{
"action" : "external_app.consent_approve" ,
"occurredAt" : "2025-01-15T10:32:00.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/consent" ,
"granted_scopes" : "openid, profile, email"
}
}
The granted_scopes field may differ from requested_scopes in the view event if the application requested scopes the user cannot grant. The system automatically filters to only grant valid scopes.
external_app.consent_reject
Records when a user rejects consent and denies permissions to an external application.
Triggered When
User clicks the “Deny” button on the consent screen, refusing to grant the requested OAuth scopes to the external application.
Event Schema
external_app.consent_reject
Same structure as external_app.login_view: external_app, mcp_proxy, and project targets
Always /external-apps/consent
Example Event
{
"action" : "external_app.consent_reject" ,
"occurredAt" : "2025-01-15T10:32:30.000Z" ,
"version" : 1 ,
"actor" : {
"type" : "user" ,
"id" : "user_01JGXYZ123" ,
"name" : "Alice Johnson" ,
"metadata" : {
"first_name" : "Alice" ,
"last_name" : "Johnson" ,
"email" : "alice@example.com" ,
"impersonator_email" : "" ,
"impersonator_reason" : ""
}
},
"targets" : [
{
"type" : "external_app" ,
"id" : "oauth_client_abc123" ,
"name" : "MCP Desktop Client" ,
"metadata" : {
"client_name" : "MCP Desktop Client" ,
"client_id" : "oauth_client_abc123"
}
},
{
"type" : "mcp_proxy" ,
"id" : "mcp_01JGXYZ789" ,
"name" : "Production API Proxy" ,
"metadata" : {
"name" : "Production API Proxy" ,
"project_id" : "proj_01JGXYZ456" ,
"organization_id" : "org_01JGXYZ001"
}
},
{
"type" : "project" ,
"id" : "proj_01JGXYZ456" ,
"name" : "Backend Services" ,
"metadata" : {
"name" : "Backend Services" ,
"organization_id" : "org_01JGXYZ001"
}
}
],
"context" : {
"location" : "192.0.2.1" ,
"userAgent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
},
"metadata" : {
"source" : "/external-apps/consent"
}
}
Authorization Security
Access Validation
All authorization requests validate that the user has access to the requested MCP proxy based on:
Project membership : User must be a member of the project containing the proxy
Proxy access scope : Proxy’s configured access restrictions (organization-wide, project-wide, or specific users)
Failed validation results in a generic error message that does not reveal the specific reason for denial. View events record user_has_access_to_proxy: false in these cases.
Challenge Expiration
OAuth challenges have a limited lifetime (typically 10 minutes). Expired challenges result in validation errors without generating audit log events, as the request is invalid before authorization begins.
External App Isolation
External applications do not belong to organizations. The external_app target contains only client metadata from the OAuth provider, not organization context. Authorization context comes from the linked MCP proxy and its parent project and organization.