Credential Lifecycle & MCP Auth
This page covers the runtime behavior of credentials — how they flow from an App to the engine, how OAuth tokens stay fresh, and how tool discovery keeps Skills in sync. Read Shared Credentials first if you haven't already.
Manifest-Driven Credential Declaration
Credentials are declared in your manifest's credentials array. Each entry includes a maps_to field that tells ORQO which field name your adapter expects when receiving credentials:
{
"credentials": [
{ "key": "GOOGLE_OAUTH2", "type": "oauth2", "label": "Google OAuth2 Token", "maps_to": "access_token" }
]
}
When ORQO passes credentials to your adapter (on /verify and /deliver calls), it maps the stored credential value to the field name specified by maps_to. This means your adapter always receives credentials with predictable field names regardless of how the credential is stored internally.
MCP Auth Bearer Token Pattern
For MCP tool calls, credentials are injected differently — as an Authorization: Bearer header. The mcp_auth field in your manifest controls where that token comes from.
{
"mcp_auth": {
"credential_key": "GOOGLE_OAUTH2",
"token_field": "access_token"
}
}
How it works
- ORQO reads
mcp_authfrom your App's configuration. - It finds the credential with key matching
credential_key. - It extracts the specified
token_fieldfrom the credential's stored fields. - It sets
Authorization: Bearer <token>as a header on all MCP requests to your adapter.
App (credentials: ["GOOGLE_OAUTH2"])
|
+-- Credential: GOOGLE_OAUTH2
| fields: access_token, refresh_token, client_id, client_secret
|
+-- mcp_auth: { credential_key: "GOOGLE_OAUTH2", token_field: "access_token" }
|
v
ORQO Engine
+-- Headers: { "Authorization": "Bearer ya29..." }
|
v
MCP HTTP request to your adapter
+-- adapter extracts Bearer token from Authorization header
The canonical OAuth credential (with refresh tokens) lives on the App. When an App is installed, ORQO creates an MCP server record and may copy a credential reference there. But the engine always reads from the App's credentials for MCP auth. If you edit the credential on the MCP server directly, those changes will be ignored for MCP auth.
Without mcp_auth
If your manifest omits mcp_auth, credentials are dumped as raw key-value headers — one header per credential field. This is the legacy pattern for non-OAuth adapters that use custom auth headers. For any new integration using OAuth, always set mcp_auth.
OAuth Token Refresh
Google access tokens expire after approximately 1 hour. Other OAuth providers have similar expiry windows. ORQO refreshes tokens automatically via a recurring background job.
How refresh works
- A background job runs on a regular schedule (currently every 45 minutes).
- The job finds all credentials with type
oauth2. - For each credential, it calls the provider's token endpoint with the stored
refresh_token. - It updates
access_tokenin the credential's stored fields. - If the provider returns a new
refresh_token, it updates that too. Otherwise, the existing refresh token is preserved.
If the refresh job runs less frequently than the token expires, MCP tool calls will fail with 401 Unauthorized between refresh cycles. Tokens that expire in 1 hour need refresh jobs running at most every 45 minutes. When adding a new OAuth provider, verify its token expiry and confirm the refresh interval is shorter.
Debugging stale tokens
If MCP tool calls start returning 401 errors:
- Check the credential's
access_token— is it recent? Look at when the credential was last updated. - Check the background job log — is the token refresh job running on schedule?
- Check the
refresh_token— has it been revoked? Some providers revoke refresh tokens after extended inactivity. - Re-authorize via OAuth if the refresh token is dead. Click Connect with OAuth on the App card to get a fresh token pair.
Tool Discovery and Sync
When you add new tools to an adapter, ORQO doesn't discover them automatically. You must trigger a sync.
How sync works
When sync runs, ORQO:
- Calls
tools/liston the adapter's MCP endpoint. - Compares the response against existing tool records.
- Creates records for any tools not yet tracked.
- Adds new tool names to the linked Skill's tool list.
- Preserves existing tool names already in the Skill — it will not remove tools you've curated out.
After deploying new tools to an adapter, the installing organization must re-verify the App. Click Verify in the UI to trigger tool discovery. Tool discovery does not happen automatically on deploy.
What triggers sync
| Action | Triggers sync? |
|---|---|
| Clicking Verify in the UI | Yes |
| Deploying a new adapter version | No |
| Restarting the adapter service | No |
| Installing an App from the marketplace | Yes (initial discovery) |
Idempotent Tool Operations
Tools that create resources (labels, folders, tags, etc.) should be idempotent. When agents retry a failed step or multiple workflow runs target the same resource, you don't want duplicates.
Pattern
def create_label(args, token):
name = args["name"]
# Check if the resource already exists
existing = list_labels(token)
match = next((l for l in existing if l["name"].lower() == name.lower()), None)
if match:
return match
# Create only if it doesn't exist
return api_client.create_label(name, token)
This prevents duplicates when:
- An agent retries after a transient error
- Multiple workflow runs create the same resource
- A user manually runs a workflow that already ran automatically
Security: Sanitization at the Trigger Boundary
Inbound event payloads (emails, webhook data, chat messages) are external content that reaches the LLM's context window. ORQO sanitizes all trigger payloads before they enter a workflow.
What ORQO sanitizes
ORQO's text sanitizer runs on every inbound payload and applies:
- Steganographic character stripping — removes zero-width characters, Unicode tag characters, and invisible formatters that could encode hidden instructions.
- Tokenade detection — flags rare Unicode codepoints that inflate token count without adding visible content.
- Combining mark capping — defends against Zalgo-style text that stacks combining marks to create visual noise.
- Injection annotation — wraps detected injection attempts with
[UNTRUSTED EXTERNAL CONTENT]markers so the LLM can identify them.
What this means for adapter developers
Adapters should NOT sanitize content themselves. Pass through raw content faithfully. ORQO handles sanitization at the platform boundary, after parse-inbound returns and before the content reaches the engine. Double-sanitization can corrupt legitimate content (e.g., stripping Unicode characters from non-Latin email bodies).
What's Next
- Adapter Contract Reference — the HTTP endpoint spec your adapter must implement
- Shared Credentials — how multiple Apps share a single credential
- Building an App — full walkthrough for creating a new App integration