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.
External OAuth and secrets
Section titled “External OAuth and secrets”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.
Declare a provider
Section titled “Declare a provider”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/connectionsDELETE {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_tokenoauth.{provider}.{connectionId}.refresh_tokenoauth.{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.