Identity & SSO: SAML, OAuth, and Access Management
Identity management is how you answer “who is this user and what can they do?” across an enterprise ecosystem. For CTA scenarios, you must design end-to-end identity solutions that span Salesforce, external systems, portals, and mobile apps — selecting the right protocols, flows, and configurations.
Identity Architecture Overview
flowchart LR
subgraph "Identity Layer"
IdP["Identity Provider\n(Who authenticates)"]
SP["Service Provider\n(Who trusts the IdP)"]
AuthZ["Authorization Server\n(Who grants access)"]
end
subgraph "Protocols"
SAML["SAML 2.0\n(Web SSO)"]
OAuth["OAuth 2.0\n(API Authorization)"]
OIDC["OpenID Connect\n(Authentication + OAuth)"]
end
subgraph "Salesforce Features"
MyDomain["My Domain"]
CA["Connected Apps"]
NC["Named Credentials"]
MFA2["MFA"]
JIT["JIT Provisioning"]
end
IdP --> SAML
IdP --> OIDC
SP --> SAML
AuthZ --> OAuth
AuthZ --> OIDC
SAML --> MyDomain
OAuth --> CA
OIDC --> CA
style IdP fill:#1565c0,color:#fff
style AuthZ fill:#2e7d32,color:#fff
style SP fill:#e65100,color:#fff
SAML 2.0 Deep Dive
SAML (Security Assertion Markup Language) is the standard for web-based single sign-on. In enterprise Salesforce deployments, SAML is almost always part of the architecture.
SAML Roles
| Role | Who Plays It | What It Does |
|---|---|---|
| Identity Provider (IdP) | Corporate IdP (Okta, Azure AD, ADFS, Ping) | Authenticates the user, issues SAML assertions |
| Service Provider (SP) | Salesforce | Trusts the IdP’s assertion, grants access |
| Principal | The user | Requests access, gets redirected |
SAML SSO Flow
sequenceDiagram
participant User
participant Browser
participant SF as Salesforce (SP)
participant IdP as Identity Provider
User->>Browser: Navigate to Salesforce URL
Browser->>SF: GET /login
SF->>Browser: 302 Redirect to IdP (SAML AuthnRequest)
Browser->>IdP: GET /sso (with AuthnRequest)
IdP->>IdP: Authenticate user (credentials, MFA)
IdP->>Browser: POST SAML Response (signed assertion)
Browser->>SF: POST /saml/SSO (SAML Response)
SF->>SF: Validate signature, extract attributes
SF->>SF: Match user (Federation ID, Username, etc.)
SF->>Browser: 302 Redirect to Salesforce home
Browser->>User: Salesforce session established
SAML Configuration Decisions
| Decision | Options | Recommendation |
|---|---|---|
| SP-initiated vs IdP-initiated | SP-initiated (user goes to SF first) or IdP-initiated (user starts at IdP portal) | Support both — SP-initiated for bookmarks, IdP-initiated for portal |
| User matching | Federation ID, Username, or Custom attribute | Federation ID — decouples from Salesforce username changes |
| JIT provisioning | Standard JIT or Custom JIT (Apex handler) | Custom JIT when you need to set profile/role/permission sets dynamically |
| Single Logout | Enabled or disabled | Enable — prevents orphaned sessions across systems |
| Certificate | IdP cert in Salesforce, SF cert for signed requests | Always validate IdP certificate; sign AuthnRequests for sensitive orgs |
Salesforce as Identity Provider
Salesforce can also act as the IdP, authenticating users for other SPs.
| Scenario | Use Case |
|---|---|
| SF as IdP to custom apps | Internal tools that need SF user authentication |
| SF as IdP to partner portals | Partners authenticate via Salesforce credentials |
| SF as IdP in multi-org | One SF org authenticates users for other SF orgs |
| SF as IdP with Connected Apps | External apps use SF login for SSO |
CTA Pattern: IdP vs SP Decision
When the scenario has an existing corporate IdP (Okta, Azure AD, ADFS), Salesforce should be the SP. When Salesforce is the system of record for users (common in customer-facing portals), Salesforce can be the IdP. In multi-org scenarios, designate one org as the IdP.
OAuth 2.0 Flows
OAuth 2.0 is the authorization framework for API access. Each flow is designed for a specific use case — choosing the wrong flow creates security vulnerabilities.
OAuth Flow Selection
flowchart TD
Start["What type of client\nneeds API access?"] --> Q1{"Is there a\nhuman user?"}
Q1 -->|Yes| Q2{"Is it a web app\nwith a server?"}
Q1 -->|No| Q3{"Is it a\nserver-to-server\nintegration?"}
Q2 -->|Yes| AuthCode["Authorization Code Flow\n(+ PKCE recommended)"]
Q2 -->|No| Q4{"Is it a mobile\nor SPA app?"}
Q4 -->|Yes| AuthCodePKCE["Authorization Code Flow\nwith PKCE (required)"]
Q4 -->|No| Device["Device Flow\n(CLI tools, IoT)"]
Q3 -->|Yes| Q5{"Does the server have\na certificate/key?"}
Q5 -->|Yes| JWT["JWT Bearer Flow"]
Q5 -->|No| ClientCred["Client Credentials Flow"]
Q1 -.->|"Already have\nSAML assertion"| SAMLBearer["SAML Bearer Flow"]
style AuthCode fill:#2e7d32,color:#fff
style AuthCodePKCE fill:#2e7d32,color:#fff
style JWT fill:#1565c0,color:#fff
style ClientCred fill:#1565c0,color:#fff
style SAMLBearer fill:#e65100,color:#fff
style Device fill:#4a148c,color:#fff
Flow 1: Authorization Code
The standard web server flow for applications with a backend.
sequenceDiagram
participant User
participant App as Web Application
participant SF as Salesforce
User->>App: Click "Login with Salesforce"
App->>SF: GET /authorize (client_id, redirect_uri, scope)
SF->>User: Login page + consent screen
User->>SF: Enter credentials + approve
SF->>App: 302 Redirect with authorization code
App->>SF: POST /token (code + client_secret)
SF->>App: Access token + refresh token
App->>SF: API calls with access token
When to use: Web applications with a secure backend server that can store the client secret.
Security considerations: The client secret must never be exposed to the browser. Always use HTTPS for redirect URIs.
Flow 2: Authorization Code with PKCE
Enhanced authorization code flow for public clients (mobile apps, SPAs) that cannot securely store a client secret.
sequenceDiagram
participant User
participant App as Mobile/SPA App
participant SF as Salesforce
App->>App: Generate code_verifier + code_challenge
App->>SF: GET /authorize (client_id, code_challenge, redirect_uri)
SF->>User: Login page + consent screen
User->>SF: Approve
SF->>App: 302 Redirect with authorization code
App->>SF: POST /token (code + code_verifier)
SF->>SF: Verify code_verifier matches code_challenge
SF->>App: Access token + refresh token
When to use: Mobile apps, single-page applications, desktop apps — any client that cannot securely store secrets.
Flow 3: JWT Bearer
Server-to-server authentication using a signed JWT. No user interaction required.
sequenceDiagram
participant Server as Integration Server
participant SF as Salesforce
Server->>Server: Create JWT (iss=client_id, sub=username, aud=login.salesforce.com)
Server->>Server: Sign JWT with private key
Server->>SF: POST /token (grant_type=jwt-bearer, assertion=signed_JWT)
SF->>SF: Validate JWT signature with stored public cert
SF->>SF: Verify claims (issuer, subject, audience, expiry)
SF->>Server: Access token (no refresh token)
When to use: Backend integrations, middleware (MuleSoft, Dell Boomi), scheduled jobs that run as a specific user.
Key details:
- Requires pre-authorized Connected App with uploaded certificate
- The
subclaim specifies which Salesforce user to impersonate - No refresh token is issued — generate a new JWT when the access token expires
- The Connected App must have “Use digital signatures” enabled
Flow 4: Client Credentials
Server-to-server flow where the integration authenticates as itself, not as a specific user.
sequenceDiagram
participant Server as Integration Server
participant SF as Salesforce
Server->>SF: POST /token (grant_type=client_credentials, client_id, client_secret)
SF->>SF: Validate credentials
SF->>SF: Run as the Connected App's designated user
SF->>Server: Access token
When to use: Service-to-service integrations where no specific user context is needed. The integration runs as the Connected App’s execution user.
Client Credentials Limitations
- Introduced in Winter ‘23 (API v56.0), broadly GA in Summer ‘23 (v58.0)
- Runs as the Connected App’s execution user — all CRUD/FLS applies to that user
- No refresh token issued
- Must be explicitly enabled on the Connected App
Flow 5: SAML Bearer
Exchanges a SAML assertion for an OAuth access token. Bridges SAML-based SSO with API access.
sequenceDiagram
participant App as Application
participant IdP as SAML IdP
participant SF as Salesforce
App->>IdP: Request SAML assertion
IdP->>App: SAML assertion (signed)
App->>SF: POST /token (grant_type=saml2-bearer, assertion=SAML)
SF->>SF: Validate SAML assertion
SF->>App: Access token
When to use: When you already have SAML infrastructure and need API access without re-authenticating the user. Common in enterprise middleware scenarios.
Flow 6: Device Flow
For devices with limited input capabilities (IoT devices, CLI tools, smart TVs).
sequenceDiagram
participant Device
participant User
participant SF as Salesforce
Device->>SF: POST /token (grant_type=device_code)
SF->>Device: device_code + user_code + verification_url
Device->>User: Display "Go to URL, enter code: ABCD-1234"
User->>SF: Navigate to URL, enter code, login, approve
loop Poll for token
Device->>SF: POST /token (device_code)
SF->>Device: authorization_pending (or access_token)
end
SF->>Device: Access token + refresh token
When to use: IoT devices, CLIs, TVs, kiosks — any device where typing credentials is impractical.
OAuth Flow Comparison
| Flow | User Interaction | Client Secret | Refresh Token | Best For |
|---|---|---|---|---|
| Authorization Code | Yes | Yes (server-side) | Yes | Web apps with backend |
| Auth Code + PKCE | Yes | No | Yes | Mobile, SPA |
| JWT Bearer | No | No (uses cert) | No | Server-to-server |
| Client Credentials | No | Yes | No | Service accounts |
| SAML Bearer | No (uses existing SAML) | No | No | SAML-to-OAuth bridge |
| Device | Yes (separate device) | No | Yes | IoT, CLI |
OpenID Connect (OIDC)
OpenID Connect adds an authentication layer on top of OAuth 2.0, providing an ID token (JWT) with user identity information. Use SAML 2.0 for enterprise web SSO with existing IdPs, OAuth 2.0 for API-only authorization, and OIDC for modern web/mobile apps needing both login and API access.
CTA Decision Framework
- Enterprise web SSO with existing IdP: SAML 2.0
- API access for integrations: OAuth 2.0 (JWT Bearer or Client Credentials)
- Modern web/mobile app needing both login and API: OpenID Connect
- Legacy system integration: SAML Bearer to bridge to OAuth
Multi-IdP and Hub-and-Spoke SSO Patterns
Enterprise scenarios often involve multiple identity providers — different business units, acquired companies, or partner organizations each with their own IdP. The CTA board expects you to know these advanced patterns.
Multi-IdP Routing Architecture
flowchart TD
User["User navigates to\nSalesforce My Domain"] --> LD["Login Discovery Page\n(My Domain login handler)"]
LD --> Route{"Route based on\nemail domain or\nuser attribute"}
Route -->|"@corp-hq.com"| IdP1["Corporate IdP\n(Azure AD)"]
Route -->|"@acquired-co.com"| IdP2["Acquired Company IdP\n(Okta)"]
Route -->|"@partner.com"| IdP3["Partner IdP\n(ADFS)"]
Route -->|"No SSO match"| Direct["Direct Salesforce Login\n(+ MFA)"]
IdP1 -->|"SAML Assertion"| SF["Salesforce\n(Service Provider)"]
IdP2 -->|"SAML Assertion"| SF
IdP3 -->|"SAML Assertion"| SF
Direct --> SF
style LD fill:#1565c0,color:#fff
style SF fill:#2e7d32,color:#fff
Hub-and-Spoke SSO (Identity Broker)
When an organization has many SPs and IdPs, an identity broker centralizes authentication routing and protocol translation.
flowchart LR
subgraph Legend
direction LR
L1[🟢 NEW]
L2[⚪ KEEPING]
L3[🔴 RETIRING]
L4[🟠 INTEGRATION LAYER]
end
subgraph "Identity Sources (Spokes)"
AD["Active Directory"]
Google["Google Workspace"]
PartnerIdP["Partner ADFS"]
end
subgraph Broker["Integration Layer — Identity Broker"]
BrokerSvc["Okta / Azure AD B2C\n(Identity Broker)"]
end
subgraph "Service Providers (Spokes)"
SF["Salesforce"]
App1["Custom Web App"]
App2["Other SaaS"]
end
AD -->|"LDAP / Kerberos\ncredentials"| BrokerSvc
Google -->|"OIDC\nID token"| BrokerSvc
PartnerIdP -->|"SAML\nassertion"| BrokerSvc
BrokerSvc -->|"SAML 2.0\nfederated assertion"| SF
BrokerSvc -->|"OIDC\nID + access token"| App1
BrokerSvc -->|"SAML 2.0\nfederated assertion"| App2
style Broker fill:#e65100,color:#fff
style BrokerSvc fill:#e65100,color:#fff
style SF fill:#1565c0,color:#fff
style AD fill:#868e96,color:#fff
style Google fill:#868e96,color:#fff
style PartnerIdP fill:#868e96,color:#fff
style App1 fill:#868e96,color:#fff
style App2 fill:#868e96,color:#fff
CTA Pattern: When to Recommend an Identity Broker
Recommend a centralized identity broker when: (1) multiple IdPs exist across business units or partner organizations, (2) different IdPs use different protocols (LDAP, Kerberos, SAML, OIDC), (3) centralized MFA enforcement is required, or (4) the organization is consolidating after M&A activity. The broker translates all protocols into a single standard (usually SAML 2.0) that Salesforce consumes.
Token Lifecycle
Understanding the OAuth token lifecycle is essential for diagnosing integration issues and designing secure token policies.
sequenceDiagram
participant Client as Client App
participant SF as Salesforce
Client->>SF: OAuth flow (authorize + token exchange)
SF->>Client: Access Token (short-lived) + Refresh Token (long-lived)
loop API Calls
Client->>SF: API request + Access Token
SF->>Client: Response (200 OK)
end
Note over Client,SF: Access Token expires (session timeout)
Client->>SF: API request + expired Access Token
SF->>Client: 401 Unauthorized
Client->>SF: POST /token (grant_type=refresh_token, refresh_token)
SF->>SF: Validate refresh token + check policy
SF->>Client: New Access Token (+ rotated Refresh Token if rotation enabled)
Note over Client,SF: Refresh Token revoked, expired, or rotated
Client->>SF: POST /token (refresh_token=revoked_token)
SF->>Client: invalid_grant error
Note over Client: Must re-authenticate via full OAuth flow
Token Policy Configuration
| Policy | Options | Security Impact |
|---|---|---|
| Refresh token expiry | Never / After X time / If unused for X time | Shorter = more secure, more re-auth friction |
| Refresh token rotation | Enabled (Spring ‘24+) / Disabled | Rotation invalidates old tokens, limiting compromise window |
| Session timeout | 15 min to 24 hours | Controls access token effective lifetime |
| Token revocation | Per user / Per Connected App / All tokens | Emergency response to compromised credentials |
Connected Apps
Connected Apps are the configuration object in Salesforce that controls OAuth and SAML integration points.
Connected App Settings That Matter
| Setting | Impact | When to Change Default |
|---|---|---|
| Permitted Users | All users / Admin approved | Set to Admin approved for sensitive integrations |
| IP Relaxation | Enforce IP restrictions or relax | Relax for mobile apps that roam networks |
| Refresh Token Policy | Expiration, rotation | Set expiration for security; rotate for compromised tokens |
| Scopes | API, refresh_token, full, web, etc. | Grant minimum required scopes |
| Callback URL | Where tokens are sent | Must match exactly; use HTTPS |
| Digital Signatures | Certificate for JWT Bearer | Required for JWT Bearer flow |
| Run As | Execution user for Client Credentials | Set to an integration user with minimum access |
My Domain
My Domain is required for SSO, Lightning components, and API access. It provides a unique, branded login URL.
My Domain Impact on Identity
- Required before configuring SAML SSO
- Required for Lightning Web Components
- Controls login page behavior (login form, SSO buttons, social sign-on)
- Can redirect automatically to IdP (skip Salesforce login page)
- Custom login flows via Login Discovery
My Domain and Existing Integrations
Deploying or changing My Domain breaks existing integrations that use the generic login.salesforce.com or instance.salesforce.com URLs. All OAuth callback URLs, SAML endpoints, and API base URLs must be updated. Plan this change carefully in large enterprises.
JIT (Just-in-Time) Provisioning
JIT provisioning automatically creates or updates Salesforce user accounts during SSO login.
Standard JIT vs Custom JIT
| Feature | Standard JIT | Custom JIT (Apex SSOJitHandler) |
|---|---|---|
| User creation | Yes, based on SAML attributes | Yes, with custom logic |
| User updates | Yes, on every login | Yes, with custom logic |
| Profile assignment | Static (one profile per SSO config) | Dynamic (based on SAML attributes or external data) |
| Permission sets | Not supported | Yes, assign dynamically |
| Role assignment | Static | Dynamic |
| Federation ID mapping | Automatic | Custom logic |
| Error handling | Limited | Full Apex exception handling |
When to Use Custom JIT
Use custom JIT (Apex SSOJitHandler) when you need to: assign profiles dynamically based on department, assign permission sets based on role, populate custom fields, create related records (contact, account), or handle complex user matching logic.
Multi-Factor Authentication (MFA)
MFA is required for all Salesforce direct logins. Understanding MFA architecture is essential for CTA scenarios.
MFA Options
| Method | Type | Best For |
|---|---|---|
| Salesforce Authenticator | Push notification + location | Most internal users |
| TOTP Authenticator apps | Time-based codes (Google Auth, Authy) | Broad compatibility |
| Security Keys (U2F/WebAuthn) | Physical hardware keys | High-security environments |
| Built-in Authenticators | Biometrics (Touch ID, Face ID, Windows Hello) | Convenience + security |
MFA in SSO Scenarios
When SSO is configured, MFA responsibility depends on the architecture:
| Scenario | Who Handles MFA | Configuration |
|---|---|---|
| Corporate IdP with MFA | IdP handles MFA before SAML assertion | No MFA config needed in Salesforce |
| Salesforce as IdP | Salesforce handles MFA | Configure MFA in Salesforce |
| SSO without IdP MFA | Must add MFA at Salesforce or IdP level | Configure either side — IdP preferred |
| Direct login fallback | Salesforce handles MFA | Always required for direct logins |
Single Logout (SLO)
Single Logout ensures that logging out of one system terminates sessions across all connected systems. Configure SLO for security-sensitive environments. IdP-initiated SLO (logout at IdP terminates all SP sessions) is most common. SP-initiated SLO (logout at Salesforce notifies IdP) is also supported but not all downstream systems honor it.
Named Credentials
Named Credentials store callout authentication details, keeping secrets out of code. See Programmatic Security for detailed Named Credential architecture and usage patterns.
Social Sign-On
Social Sign-On (Google, Facebook, LinkedIn, Apple) is best suited for customer portals where it reduces friction for consumer users. For partner portals, LinkedIn provides professional identity verification. For internal Salesforce, always prefer corporate SSO over social sign-on.
Related Topics
- Sharing Model — identity determines who the user is; sharing determines what they see
- Portal Security — external user identity and authentication patterns
- Field & Object Security — permissions assigned after authentication
- Decision Guides — identity architecture and OAuth flow decision trees
- Programmatic Security — Named Credentials and secure callouts
- Integration — OAuth flows for API-based integrations
Sources
- Salesforce Help: SAML Single Sign-On
- Salesforce Help: OAuth 2.0 Authentication Flows
- Salesforce Help: Connected Apps
- Salesforce Help: My Domain
- Salesforce Help: MFA
- Salesforce Help: OAuth Refresh Token Flow
- Salesforce Help: Refresh Token Rotation (Spring ‘24)
- Salesforce Help: Manage OAuth Access Policies
- Salesforce Architects: Identity Architecture
- Cloud Sundial: Salesforce SSO Flows
- Cloud Sundial: Salesforce Identity Flows
- RFC 6749: OAuth 2.0 Authorization Framework
- RFC 7523: JWT Bearer Token
- OpenID Foundation: OpenID Connect Core