Identity & SSO: Quick Reference
Fast-track reference for identity and SSO — know the protocols, flows, and when to use each before you walk into a mock board.
Protocol Cheat Sheet
| Protocol | Purpose | Token/Assertion | Use When |
|---|---|---|---|
| SAML 2.0 | Web SSO (authentication) | XML assertion | Enterprise SSO with existing IdP |
| OAuth 2.0 | API authorization | Access token + refresh token | Integrations needing API access |
| OpenID Connect | Authentication + authorization | ID token (JWT) + access token | Modern web/mobile apps needing both login and API |
One-Line Decision
Enterprise web SSO = SAML. API access = OAuth. Modern app needing both = OIDC. Legacy bridge = SAML Bearer.
IdP vs SP Decision
flowchart TD
Q1{"Does the customer have\nan existing corporate IdP?"} -->|"Yes (Okta, Azure AD,\nADFS, Ping)"| SP["Salesforce = SP\nCorporate IdP authenticates"]
Q1 -->|No| Q2{"Is Salesforce the\nuser system of record?"}
Q2 -->|Yes| IdP["Salesforce = IdP\n(common for portals)"]
Q2 -->|No| NewIdP["Recommend dedicated IdP\nSalesforce = SP"]
style SP fill:#1565c0,color:#fff
style IdP fill:#2e7d32,color:#fff
style NewIdP fill:#e65100,color:#fff
| Scenario | Salesforce Role | Protocol |
|---|---|---|
| Corporate IdP exists | Service Provider | SAML 2.0 or OIDC |
| SF is user SOR (portals, small company) | Identity Provider | SAML/OIDC via Connected Apps |
| Multi-org architecture | One org = IdP, others = SP | SAML 2.0 |
| No IdP anywhere | Recommend Okta/Azure AD; SF = SP | SAML 2.0 |
SAML SSO Key Decisions
| Decision | Options | Board-Ready Answer |
|---|---|---|
| User matching | Federation ID, Username, Custom | Federation ID — survives username changes |
| SP vs IdP initiated | SP-initiated, IdP-initiated | Support both. SP for bookmarks, IdP for portal |
| JIT provisioning | Standard JIT, Custom JIT (Apex) | Custom JIT when profile/role/PS must be dynamic |
| Single Logout | Enabled, Disabled | Enable for security-sensitive environments |
| MFA | IdP handles, SF handles | IdP-based MFA preferred; satisfies SF MFA requirement |
OAuth Flow Selection (The Big Table)
| Flow | User Interaction | Secret/Cert | Refresh Token | Use For |
|---|---|---|---|---|
| Authorization Code | Yes | Client secret (server) | Yes | Web apps with backend |
| Auth Code + PKCE | Yes | No secret needed | Yes | Mobile apps, SPAs |
| JWT Bearer | No | Certificate | No | Server-to-server, middleware |
| Client Credentials | No | Client secret | No | Service accounts (API v56.0+; Winter ‘23, broadly GA Spring ‘23) |
| SAML Bearer | No | SAML assertion | No | SAML-to-OAuth bridge |
| Device | Yes (separate device) | No | Yes | IoT, CLI tools |
OAuth Flow Decision Tree
flowchart TD
Start["App needs API access"] --> Q1{"Human user\ninvolved?"}
Q1 -->|Yes| Q2{"App has\nbackend server?"}
Q1 -->|No| Q3{"Has certificate?"}
Q2 -->|Yes| AC["Auth Code\n+ PKCE recommended"]
Q2 -->|No| PKCE["Auth Code + PKCE\nREQUIRED"]
Q3 -->|Yes| JWT["JWT Bearer"]
Q3 -->|No| CC["Client Credentials"]
Q1 -.->|"Has SAML\nassertion"| SB["SAML Bearer"]
style AC fill:#2e7d32,color:#fff
style PKCE fill:#2e7d32,color:#fff
style JWT fill:#1565c0,color:#fff
style CC fill:#1565c0,color:#fff
style SB fill:#e65100,color:#fff
Deprecated Flow
The Username-Password flow is deprecated. Never recommend it. If the scenario has a legacy system using it, recommend migrating to JWT Bearer or Client Credentials.
PKCE Flow — How It Works
What PKCE solves: Public clients (mobile apps, SPAs) cannot securely store a client secret. Without PKCE, an attacker who intercepts the authorization code can exchange it for an access token. PKCE (RFC 7636) binds the authorization request to the token request using a one-time cryptographic proof that only the original client possesses.
sequenceDiagram
participant App as Mobile / SPA
participant SF as Salesforce
participant User
App->>App: Generate random code_verifier (43-128 chars)
App->>App: code_challenge = BASE64URL(SHA256(code_verifier))
App->>SF: GET /authorize (client_id, code_challenge, method=S256, redirect_uri)
SF->>User: Login page + consent screen
User->>SF: Authenticate + approve
SF->>SF: Store code_challenge with auth code
SF->>App: 302 Redirect with authorization code
App->>SF: POST /token (code + code_verifier, NO client secret)
SF->>SF: Compute SHA256(code_verifier), compare to stored code_challenge
SF->>App: Access token + refresh token
Board Q&A — PKCE
“Why can’t an attacker intercept the auth code and use it?” — They don’t have the code_verifier. The code alone is useless without the original random value that produced the challenge.
“Why not just use a client secret?” — Public clients (mobile, SPA) ship code to the user’s device. A secret embedded there can be extracted. PKCE replaces the static secret with a per-request cryptographic proof.
“When is PKCE required vs optional in Salesforce?” — Required for mobile/SPA (uncheck “Require Secret for Web Server Flow” on the Connected App). Recommended for all authorization code flows per OAuth 2.1.
JWT Bearer Flow — How It Works
What JWT Bearer solves: Server-to-server integrations (middleware, ETL, scheduled jobs) need API access without a human present. JWT Bearer (RFC 7523) lets the server prove its identity with a digitally signed token instead of user credentials, running as a pre-authorized Salesforce user.
sequenceDiagram
participant Srv as Integration Server
participant SF as Salesforce
Srv->>Srv: Build JWT: iss=client_id, sub=sf_username, aud=login.salesforce.com, exp=now+3min
Srv->>Srv: Sign JWT with private key (RS256)
Srv->>SF: POST /services/oauth2/token (grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer, assertion=signed_JWT)
SF->>SF: Look up Connected App by iss (client_id)
SF->>SF: Retrieve stored X.509 public certificate
SF->>SF: Validate signature, check exp ≤ 5 min, verify aud + sub
SF->>Srv: Access token (NO refresh token)
Board Q&A — JWT Bearer
“Why no refresh token?” — The private key IS the long-lived credential. When the access token expires, just sign and send a new JWT. No refresh dance needed.
“What happens if the certificate expires?” — All integrations using that Connected App fail silently. You must rotate the certificate and upload the new public cert to the Connected App before expiry. Monitor cert expiry dates proactively.
“JWT Bearer vs Client Credentials — when?” — JWT Bearer when you need to act as a specific named user (sub claim controls which user’s permissions apply). Client Credentials when the integration runs as a generic service account with its own execution user.
Connected App Key Settings
| Setting | What It Controls | CTA Guidance |
|---|---|---|
| Permitted Users | Who can use the app | Set to “Admin approved” for sensitive integrations |
| IP Relaxation | IP enforcement | Relax for mobile apps that roam networks |
| Refresh Token Policy | Token expiration/rotation | Set expiration; rotate for compromised tokens |
| Scopes | API access breadth | Minimum required scopes only — never “full” unless justified |
| Callback URL | Token delivery endpoint | Must match exactly; HTTPS only |
| Digital Signatures | Certificate for JWT Bearer | Required for JWT Bearer flow |
| Run As | Execution user (Client Credentials) | Integration user with minimum access |
JIT Provisioning Comparison
| Feature | Standard JIT | Custom JIT (Apex SSOJitHandler) |
|---|---|---|
| User creation | Yes | Yes, with custom logic |
| Profile assignment | Static (one per SSO config) | Dynamic (based on attributes) |
| Permission Set assignment | No | Yes |
| Role assignment | Static | Dynamic |
| Related record creation | No | Yes (Contact, Account) |
Use Custom JIT when you need to assign profiles/roles/permission sets dynamically based on SAML attributes or external data.
MFA Quick Reference
| When SSO is configured | Who handles MFA |
|---|---|
| Corporate IdP has MFA | IdP handles it — no SF MFA config needed |
| SSO without IdP MFA | Must add MFA at IdP or SF level (IdP preferred) |
| Salesforce as IdP | SF handles MFA |
| Direct login fallback | SF MFA always required |
Breakglass Accounts
Always configure 2-3 admin accounts that bypass SSO for emergency access. If the IdP goes down, you need a way in. These accounts must have MFA enabled for direct login.
Named Credentials (Modern Architecture)
| Legacy Model | Enhanced Model (Current) |
|---|---|
| Single Named Credential = endpoint + auth | Named Credential = endpoint URL |
| Auth config embedded | External Credential = auth config (separate) |
| Per-user or named principal | Permission Set controls who can use it |
| N/A | Multiple Named Credentials share one External Credential |
Always use Named Credentials for callouts. Never hardcode credentials in Apex, Custom Settings, or Custom Metadata.
Scenario 1: Enterprise SSO + API Integration
Situation: Financial services company. 10,000 internal users on Okta. MuleSoft middleware connects Salesforce to core banking. Mobile app for field agents. Regulatory requirement for MFA.
What you’d present:
- Salesforce = SP, Okta = IdP, protocol = SAML 2.0
- User matching via Federation ID (decoupled from SF username)
- Custom JIT provisioning (Apex handler assigns profile/PS based on Okta group attributes)
- MFA handled by Okta (satisfies Salesforce MFA requirement)
- MuleSoft to Salesforce: JWT Bearer flow (server-to-server, certificate-based, no user interaction)
- Mobile app: Authorization Code + PKCE (public client, cannot store secrets)
- Single Logout enabled (regulatory compliance)
- 2 breakglass admin accounts with direct login + SF MFA
Why not Client Credentials for MuleSoft: JWT Bearer lets MuleSoft impersonate specific integration users with different permission levels per flow. Client Credentials runs as a single execution user.
Scenario 2: Multi-Org with Customer Portal
Situation: Retail company with 2 Salesforce orgs (Sales, Service). Customer self-service portal on the Service org. 50,000 portal users. No corporate IdP.
What you’d present:
- Service org = IdP (system of record for customer users)
- Sales org = SP (trusts Service org for internal user SSO via SAML)
- Portal users authenticate directly against Service org (Salesforce login)
- Social Sign-On enabled for portal (Google, Apple) to reduce friction
- Standard JIT provisioning for internal users logging into Sales org from Service org IdP
- Portal API access: Auth Code + PKCE (customer-facing mobile app)
- Named Credentials for org-to-org callouts (Service —> Sales for order data)
Why Salesforce as IdP: No corporate IdP exists, and Salesforce is the user SOR for both internal and portal users. Recommending a dedicated IdP (Okta) would add cost and complexity that the scenario does not justify.
Scenario 3: Legacy System Bridge
Situation: Manufacturing company with on-prem SAP system that uses SAML-based SSO. A new middleware layer needs to call Salesforce APIs on behalf of users who are already authenticated via SAML.
What you’d present:
- SAML Bearer flow — exchanges the existing SAML assertion for a Salesforce OAuth access token
- No re-authentication required (user already proved identity to SAP’s IdP)
- Connected App configured with SAML assertion settings
- Named Credentials on the Salesforce side for any callouts back to SAP
- Plan to migrate toward JWT Bearer as the middleware modernizes
Why SAML Bearer: The middleware already has a valid SAML assertion. SAML Bearer avoids re-authentication and bridges the existing SAML infrastructure to OAuth-based API access.
Deep Dive References
- Identity & SSO: Full Deep Dive
- Security Decision Guides: OAuth Flow & Identity Trees
- Programmatic Security: Named Credentials