OAuthSentry

API Documentation

OAuthSentry exposes a REST API for programmatic scanning, live threat intelligence, Linear ticket filing, Slack alerting, and scheduled scan management. All endpoints are available at https://oauthsentry-phi.vercel.app.

Streaming scan

NDJSON

Live threat feed

NVD · OSV · GitHub

Slack + Linear

Real alerts

Scheduled scans

Upstash Redis

Authentication

Endpoints marked api-key require your API key set in the Settings dialog in the app (for Linear and Slack integrations), or as environment variables on the server. For programmatic access:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  https://oauthsentry-phi.vercel.app/api/scan

LINEAR_API_KEY — Linear API key (from linear.app/settings/account/security)

SLACK_WEBHOOK_URL — Slack Incoming Webhook URL

KV_REST_API_URL / KV_REST_API_TOKEN — Upstash Redis (for scheduled scans)

Endpoints (8)

POST
/api/scanStreaming NDJSON

Run an AI-powered security scan on a list of assets (OAuth apps, npm packages, SaaS tools). Returns a streaming NDJSON response — each line is a JSON event as findings are produced.

Request Body

FieldTypeDescription
assetsAsset[]Array of assets to scan (max 40)
assets[].idstringUnique identifier for the asset
assets[].kind'oauth_app' | 'npm_package' | 'saas_tool'Asset category
assets[].namestringHuman-readable name
assets[].identifierstringOAuth client ID, npm package name, or domain
assets[].ownerstringWho installed or owns this asset
assets[].scopesstring[]OAuth/permission scopes granted

Response

FieldTypeDescription
type'start' | 'finding' | 'error' | 'done'Event type for each NDJSON line
finding.scorenumber (0–100)Risk score — higher means riskier
finding.level'critical' | 'high' | 'medium' | 'low' | 'info'Risk severity level
finding.headlinestringShort summary of the identified risk
finding.reasoningstringDetailed AI-generated reasoning
finding.factors{ label: string; detail: string }[]Individual risk factor breakdown
finding.iocMatchesstring[]Matched IOC IDs from threat feeds
finding.recommendationstringActionable remediation steps

Example

Request

POST /api/scan
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "assets": [
    {
      "id": "oauth-context-ai",
      "kind": "oauth_app",
      "name": "Context.ai",
      "identifier": "110671459871-30f1spbu0hptbs60cb4vsmv791tbbvqj.apps.googleusercontent.com",
      "scopes": ["gmail.readonly", "calendar.modify", "contacts.readonly"]
    }
  ]
}

Response

{"type":"start","count":1}
{"type":"finding","finding":{"assetId":"oauth-context-ai","score":95,"level":"critical","headline":"OAuth app involved in major security breach","reasoning":"Context.ai was the vector for the April 2026 Vercel/Context.ai incident...","factors":[{"label":"Breach Confirmed","detail":"Listed in NVD and GitHub Security Advisories"}],"iocMatches":["ioc-context-ai-2026"],"recommendation":"Immediately revoke all permissions..."},"analyzed":1,"total":1}
{"type":"done","analyzed":1}
GET
/api/threat-feedLive — NVD · OSV · GitHubNo auth required

Fetch live threat intelligence from NVD, OSV (Google), and GitHub Security Advisories. Results are aggregated, sorted by date, and cached for 1 hour to respect upstream rate limits.

Response

FieldTypeDescription
itemsThreatItem[]Array of up to 15 live threat items sorted newest-first
items[].idstringCVE ID, GHSA ID, or OSV ID
items[].titlestringShort title of the threat
items[].summarystringDetailed description
items[].severity'critical' | 'high' | 'medium' | 'low' | 'info'Severity mapped from CVSS score
items[].indicatorKind'oauth_client' | 'npm' | 'domain' | 'cve'Type of threat indicator
items[].indicatorstringThe affected identifier (package name, CVE ID, domain)
items[].source'NVD' | 'OSV' | 'GITHUB SECURITY'Source of the threat intelligence
items[].referencestring (URL)Direct link to advisory
items[].publishedAtISO 8601 stringWhen this advisory was published
fetchedAtISO 8601 stringTimestamp of this response

Example

Response

{
  "items": [
    {
      "id": "CVE-2026-12345",
      "title": "CVE-2026-12345: Critical RCE in oauth2-proxy...",
      "summary": "A heap buffer overflow in oauth2-proxy allows remote code execution via malformed token.",
      "severity": "critical",
      "indicatorKind": "cve",
      "indicator": "CVE-2026-12345",
      "source": "NVD",
      "reference": "https://nvd.nist.gov/vuln/detail/CVE-2026-12345",
      "publishedAt": "2026-04-29T00:00:00Z"
    }
  ],
  "sources": ["NVD", "OSV", "GitHub Security"],
  "fetchedAt": "2026-05-03T12:00:00Z"
}
POST
/api/actions/file-ticket

Create a Linear issue for a specific risk finding. Uses the API key from the request body (set in Settings) or falls back to the LINEAR_API_KEY environment variable.

Request Body

FieldTypeDescription
findingRiskFindingThe full finding object from a scan result
finding.asset.namestringAsset name for the ticket title
finding.scorenumberRisk score (0–100)
finding.levelstringSeverity level
finding.headlinestringIssue title
finding.reasoningstringIssue description body
finding.recommendationstringRemediation steps in the ticket
linearApiKeystringLinear API key (overrides env var)

Response

FieldTypeDescription
successbooleanWhether the ticket was created
ticketUrlstring (URL)Direct URL to the Linear issue
ticketIdstringLinear issue ID (e.g. OAU-42)
errorstringError message if success is false

Example

Response

{
  "success": true,
  "ticketUrl": "https://linear.app/oauthsentry/issue/OAU-42",
  "ticketId": "OAU-42"
}
POST
/api/actions/send-alert

Send a rich Slack message to your webhook for a risk finding. Uses the webhook URL from the request body (set in Settings) or falls back to the SLACK_WEBHOOK_URL environment variable.

Request Body

FieldTypeDescription
findingRiskFindingThe full finding object from a scan result
finding.asset.namestringAsset name displayed in the alert
finding.scorenumberRisk score shown in the alert
finding.headlinestringAlert summary headline
finding.cveReferences{ id: string; score: number }[]CVE data shown in threat intelligence section
slackWebhookUrlstring (URL)Slack webhook URL (overrides env var)

Response

FieldTypeDescription
successbooleanWhether the alert was delivered
errorstringError message if success is false

Example

Response

{
  "success": true
}
GET
/api/scheduled-scans

Retrieve all saved scheduled scan configurations from Upstash Redis.

Response

FieldTypeDescription
successbooleanWhether the request succeeded
schedulesScheduleConfig[]Array of all saved schedules
schedules[].idstringUnique schedule ID
schedules[].frequency'daily' | 'weekly' | 'monthly'How often the scan runs
schedules[].timestring (HH:MM)Time of day to run
schedules[].recipientsstring[]Email addresses for reports
schedules[].enabledbooleanWhether this schedule is active
schedules[].nextRunISO 8601 stringWhen this scan will next execute
schedules[].lastRunISO 8601 stringWhen this scan last ran (if ever)

Example

Response

{
  "success": true,
  "schedules": [
    {
      "id": "schedule-1746123456-abc123",
      "frequency": "daily",
      "time": "09:00",
      "recipients": ["security@company.com"],
      "includeCharts": true,
      "includeRecommendations": true,
      "enabled": true,
      "createdAt": "2026-05-01T00:00:00Z",
      "nextRun": "2026-05-04T09:00:00Z",
      "lastRun": "2026-05-03T09:00:00Z"
    }
  ]
}
POST
/api/scheduled-scans

Create a new scheduled scan configuration. The schedule is persisted to Upstash Redis and the next run time is calculated automatically.

Request Body

FieldTypeDescription
frequency'daily' | 'weekly' | 'monthly'How often to run the scan
timestring (HH:MM)Time of day to run (24h format)
dayOfWeeknumber (0–6)Day of week for weekly schedules (0=Sunday)
dayOfMonthnumber (1–31)Day of month for monthly schedules
recipientsstring[]Email addresses to notify
includeChartsbooleanInclude visual charts in report (default: true)
includeRecommendationsbooleanInclude remediation steps (default: true)

Response

FieldTypeDescription
successbooleanWhether the schedule was saved
scheduleScheduleConfigThe created schedule with computed nextRun

Example

Response

{
  "success": true,
  "schedule": {
    "id": "schedule-1746123456-abc123",
    "frequency": "daily",
    "time": "09:00",
    "enabled": true,
    "nextRun": "2026-05-04T09:00:00Z",
    "createdAt": "2026-05-03T12:00:00Z"
  }
}
POST
/api/scheduled-scans/executeVercel Cron every 15 min

Immediately execute a specific scheduled scan by ID, or run all due scans when called by Vercel Cron (every 15 minutes). Returns scan results including findings summary.

Request Body

FieldTypeDescription
scheduleIdstringSpecific schedule ID to run. Omit to run all due schedules (Cron mode)

Response

FieldTypeDescription
successbooleanWhether the scan executed
result.findingsCountnumberTotal findings from this scan
result.criticalCountnumberNumber of critical severity findings
result.highCountnumberNumber of high severity findings
result.ranAtISO 8601 stringWhen this execution ran

Example

Request

POST /api/scheduled-scans/execute
Content-Type: application/json

{ "scheduleId": "schedule-1746123456-abc123" }

Response

{
  "success": true,
  "result": {
    "findingsCount": 5,
    "criticalCount": 2,
    "highCount": 2,
    "ranAt": "2026-05-03T12:00:00Z"
  }
}
POST
/api/workflow

Trigger a durable WDK (Workflow Development Kit) scan workflow that enumerates assets from Google Workspace, GitHub, npm, and SaaS tools, then runs the AI scan agent, and posts Slack alerts for critical findings.

Request Body

FieldTypeDescription
trigger'manual-scan'Trigger type — only 'manual-scan' is supported

Response

FieldTypeDescription
runIdstringThe durable workflow run ID for tracking
status'started'Confirmation the workflow was started

Example

Request

POST /api/workflow
Content-Type: application/json

{ "trigger": "manual-scan" }

Response

{
  "runId": "wf_9x3kZ1mNpQ2rT8",
  "status": "started"
}

Error Codes

StatusMeaningCommon cause
200 OKSuccessRequest processed correctly
400 Bad RequestInvalid requestMissing required fields or wrong types — check Zod schema errors in response
401 UnauthorizedAuthentication requiredLINEAR_API_KEY or SLACK_WEBHOOK_URL not configured
404 Not FoundResource missingSchedule ID not found in Upstash Redis
429 Too Many RequestsRate limitedNVD or GitHub APIs are rate-limited — the threat feed caches for 1 hour to mitigate this
500 Internal Server ErrorServer errorAI Gateway failure, upstream API error, or Upstash Redis connection issue

Rate Limits

  • /api/scan — Max 40 assets per request. AI Gateway token limits apply per model.
  • /api/threat-feed — Cached for 1 hour. NVD free tier: 5 requests/30s without API key.
  • /api/actions/* — Slack webhook: no hard limit. Linear: 1,500 req/hour.
  • /api/scheduled-scans/execute — Triggered by Vercel Cron every 15 minutes.

View source, open issues, or contribute at github.com/HayreKhan750/oauthsentry