# Authentication & Security

Fours connects to your Salesforce org via the **OAuth 2.0 Authorization Code flow with PKCE** ([RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)). The Fours External Client App is configured for compliance with Salesforce's Connected App security requirements.

## What Fours never sees

- Your Salesforce user's **password**. The user authenticates directly with Salesforce; only an authorization code is returned to Fours.
- No **static API key or long-lived bearer token** for your org. Every API call uses a short-lived access token.
- Fours' **client secret** stays on Fours' backend and is never exposed to the browser.

## Mandate-compliant authentication

The Fours External Client App enforces the four security controls required by Salesforce's May 2026 mandate. These are configured at the app level and travel with the managed package install — you don't configure them per-org.

| Control | What it does |
| :-- | :-- |
| **PKCE** ([RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)) | The browser-side authorization code is bound to a one-time `code_verifier` held only by Fours' backend. A stolen authorization code cannot be redeemed without it. |
| **Refresh Token Rotation** | Every refresh issues a new RT and invalidates the prior one. A leaked RT becomes useless on first reuse, and Salesforce detects reuse and revokes the entire grant. |
| **Idle TTL: 30 days** | A refresh token unused for 30 days is automatically revoked. Fours' 30-minute cron keeps the timer well under this limit. |
| **IP Allowlist** | Refresh requests are only accepted from Fours' published NAT egress IPs. Contact support for the current list. |

## Authorization flow (first-time connect)

1. **Browser redirect** to Salesforce with a PKCE `code_challenge` and signed state.
2. **User consent** at Salesforce (SSO/MFA per your org policy).
3. **Authorization code** returned to Fours' callback.
4. **Server-side token exchange** with `code_verifier`, returning an access token and refresh token. Neither passes through the browser.
5. **Credentials stored** in AWS Secrets Manager (KMS-encrypted, IAM-scoped).

The line between the browser and the backend is what the flow is built around: the browser only ever carries the authorization code, and the `code_verifier` that redeems it never leaves Fours' backend.

```d2
shape: sequence_diagram

admin: "Your admin\n(browser)"
sf: "Salesforce"
suger: "Fours backend"
vault: "AWS Secrets Manager"

admin -> sf: "1. redirect with code_challenge + signed state"
sf -> admin: "2. consent (SSO / MFA per your org policy)"
admin -> suger: "3. authorization code on the callback"
suger -> sf: "4. token exchange with code_verifier\n(server to server, never in the browser)"
sf -> suger: "access token + refresh token"
suger -> vault: "5. store credentials (KMS-encrypted, IAM-scoped)"

refresh: "Automatic refresh — every ~2h, 3 min before expiry" {
  suger -> vault: "read current refresh token"
  suger -> sf: "refresh"
  sf -> suger: "new access token + rotated refresh token\n(the previous one is invalidated)"
  suger -> vault: "persist the rotated pair"
}

revoke: "Revocation" {
  admin -> sf: "revoke in Salesforce — all tokens die,\nFours' next call is rejected"
  admin -> suger: "delete in Fours Console — the stored secret is removed"
  suger -> vault: "delete secret"
}
```

## Automatic refresh

Access tokens are ~2 hours by default and can be longer depending on your org's Session Policy. Before they expire (3-minute safety buffer), Fours exchanges the refresh token for a new pair and persists the rotated credentials to AWS Secrets Manager. The refresh flow is coordinated across Fours' infrastructure to remain fully compatible with Refresh Token Rotation.

## Token storage

| Credential | Storage | Encryption |
| :-- | :-- | :-- |
| Access token, refresh token, client secret | AWS Secrets Manager | AES-256 via AWS KMS |
| Instance URL, expiration, username | Application database | Provider-managed at rest |

IAM-scoped access, CloudTrail-audited reads. No standing employee access.

## Scopes and least privilege

Fours requests only the OAuth scopes needed for features you've opted into. Inside your Salesforce org, the **Integration User's Profile and Permission Sets** are the authoritative access boundary — they apply regardless of OAuth scope. See [Permission Sets](/salesforce-app/salesforce-app-permission-sets/).

## Required OAuth policy settings (admin)

The Fours External Client App ships with mandate-compliant defaults. The settings below are the ones your admin still controls. Open them at **Setup → External Client App Manager → Suger → Policies tab → Edit**.

| Setting | Required value | Why |
| :-- | :-- | :-- |
| **Permitted Users** | `Admin approved users are pre-authorized` **or** `All users may self-authorize` | With pre-authorized, you must list the Integration User's profile or permission set under **Selected Profiles/Permission Sets**, otherwise OAuth fails with *"Not approved for access"*. |
| **IP Relaxation** | `Relax IP restrictions` **or** allowlist Fours' egress IPs | If you `Enforce IP restrictions`, add Fours' egress IPs to **Profile → Login IP Ranges** and (if your org enforces it) **Network Access → Trusted IP Ranges**. |
| **High Assurance Session Required** | Off | An MFA-verified session can't be satisfied by a server-to-server integration. |
| **Selected Profiles / Permission Sets** | Must include the Integration User's profile or an assigned permission set | Only enforced when `Permitted Users = Admin approved`. |

> Tightening these on a live integration may require reconnecting it: in **Fours Console → Settings → Integrations**, open the **⋯** menu on the verified Salesforce card and choose **Reconnect**. Reconnect replaces the stored credential and keeps the integration's settings. Fours asks Salesforce for a fresh sign-in, pre-filled with the connected user — sign in as that user. When the confirmation dialog names the connected user and you sign in as someone else, Fours cancels the reconnect and nothing changes, unless you checked **Change the connected Salesforce user**. See [Reconnect the integration](/integrations/salesforce/#reconnect-the-integration).

## Transport security

All Fours ↔ Salesforce traffic — authorize, callback, `/token`, introspect, REST — uses **TLS 1.2 or higher**.

## Revocation and deletion

- **Revoke in Salesforce**: invalidates all tokens; Fours' next call is rejected.
- **Delete in Fours Console**: removes the AWS Secrets Manager secret; no further calls to your org.

See the [Salesforce Integration Setup Guide](/integrations/salesforce/#removing-the-integration) for step-by-step removal instructions.

## Summary

| Property | Value |
| :-- | :-- |
| OAuth flow | Authorization Code + PKCE (RFC 6749, RFC 7636) |
| Refresh Token Rotation | Enforced |
| Idle TTL | 30 days |
| IP allowlist | Enforced (Fours egress IPs) |
| Access token lifetime | ~2h (per your Session Policy) |
| Credential storage | AWS Secrets Manager (KMS, IAM, CloudTrail) |
| Transport | TLS 1.2+ |
| Access boundary | Profile + Permission Sets on the Integration User |
| Revocation | Immediate, from either side |
