Skip to content

Connect an app to an external OAuth provider

Connect an installed Caraer app to a service such as Google or Microsoft. This is separate from the app’s Caraer authentication method. You need a provider client, the provider’s registered callback settings, and a sandbox installation. Keep provider-specific mappings in your app.

authMethod is how the company installs the Caraer app. externalOAuthProviders is how an installer (or each user) connects a third-party account such as Google Calendar. They are independent: a typical hosted sync app is authMethod: NONE plus one or more external providers.

There are also two kinds of secret:

Kind Where Who sees it Example
Deploy-time env Root .env, packed into the container Your function as process.env / os.environ GOOGLE_CLIENT_SECRET
Installation vault Encrypted on the HAS_APP install Injected on body.secrets at invoke time gmail_access_token, your own API keys

Do not commit .env. Do not put OAuth client secrets in settingsSchema.

externalOAuthProviders:
- name: gmail
label: Google Calendar
connectionOwner: USER # or COMPANY (default)
authorizeUrl: https://accounts.google.com/o/oauth2/v2/auth
tokenUrl: https://oauth2.googleapis.com/token
clientId: ${GOOGLE_CLIENT_ID}
clientSecret: ${GOOGLE_CLIENT_SECRET}
scopes:
- https://www.googleapis.com/auth/calendar.events
- https://www.googleapis.com/auth/calendar.readonly
- https://www.googleapis.com/auth/userinfo.email

${ENV_VAR} fields expand on caraer apps push from the process environment or root .env. The CLI never writes the raw client secret into the persisted manifest.

connectionOwner Who connects Tokens on invoke
COMPANY (default) One shared account per install body.secrets.gmail_access_token / gmail_refresh_token, and body.connections[]
USER One account per Caraer user body.connections[] (plus connection-scoped keys in body.secrets)

Connect is not a lifecycle webhook. The installer uses the Connect button in Caraer, or your code starts it:

POST {caraerApiBase}/v2/apps/{appUuid}/installation/oauth/{provider}/start?redirectUri=...
Authorization: Bearer <installationToken>

That returns { "authorizeUrl" }. Open it in the browser. After callback, Caraer stores tokens in the vault and refreshes them before the next invoke when they are close to expiry.

Status and revoke:

GET {caraerApiBase}/v2/apps/{appUuid}/installation/connections
DELETE {caraerApiBase}/v2/apps/{appUuid}/installation/connections/{providerOrConnectionId}

body.connections[] looks like:

{
"id": "…",
"provider": "gmail",
"ownerType": "USER",
"ownerUserUuid": "…",
"accountLabel": "ada@example.com",
"connectedAt": 1774272000000,
"accessToken": "ya29.…"
}

Connection-scoped vault keys (always present after connect):

  • oauth.{provider}.{connectionId}.access_token
  • oauth.{provider}.{connectionId}.refresh_token
  • oauth.{provider}.{connectionId}.access_token_expires_at

For COMPANY connections Caraer also mirrors the legacy aliases {provider}_access_token, {provider}_refresh_token, and {provider}_access_token_expires_at.

Per-user picks (which calendars to sync) belong in settings with valueScope: USER, saved via PUT {caraerApiBase}/v2/apps/{appUuid}/installation/settings/user. That fires app.updated with userSettingsChanged: true.