Field & Object Security: Profiles, Permission Sets & FLS
Field and object security controls what users can do with data — which objects they can access, which fields they can see, and what CRUD operations they can perform. While the sharing model controls which records a user can see, field and object security controls what they can do with those records.
flowchart LR
subgraph "Record Access (Which records?)"
OWD["OWD"]
RH["Role Hierarchy"]
SR["Sharing Rules"]
end
subgraph "Object & Field Access (What can they do?)"
Profile["Profile"]
PS["Permission Sets"]
PSG["Permission Set Groups"]
FLS["Field-Level Security"]
end
OWD --> Profile
RH --> PS
SR --> PSG
Profile --> FLS
PS --> FLS
PSG --> FLS
style Profile fill:#1565c0,color:#fff
style PS fill:#2e7d32,color:#fff
style PSG fill:#e65100,color:#fff
Profiles
A Profile is the baseline permission assignment for a user. Every user must have exactly one Profile.
What Profiles Control
| Category | Permissions |
|---|---|
| Object permissions | Create, Read, Edit, Delete, View All, Modify All |
| Field-level security | Visible, Read Only, Hidden per field per object |
| Tab visibility | Default On, Default Off, Hidden |
| App visibility | Which Lightning apps are visible |
| Record types | Which record types are available + default |
| Page layouts | Which page layout to display per record type |
| Login hours | When the user can log in |
| Login IP ranges | Where the user can log in from |
| System permissions | API Enabled, Author Apex, Manage Users, etc. |
| Apex class access | Which Apex classes are executable |
| Visualforce page access | Which VF pages are accessible |
| Connected App access | Which Connected Apps are available |
The Minimum Access Profile Pattern
CTA Best Practice: Minimum Access Profile
The recommended pattern for enterprise Salesforce is to create a Minimum Access Profile (or use the built-in “Minimum Access - Salesforce” profile) that grants almost nothing, then layer permissions using Permission Sets. This is analogous to starting with Private OWD for sharing.
Why minimum access profiles?
| Traditional Approach | Minimum Access + Permission Sets |
|---|---|
| Multiple profiles (one per role) | One or few base profiles |
| Hard to audit — permissions scattered across profiles | Easy to audit — each Permission Set has a clear purpose |
| Profile cloning creates drift | Permission Sets are reusable building blocks |
| Changing a profile affects all assigned users | Permission Sets can be assigned selectively |
| Cannot assign multiple profiles | Can stack multiple Permission Sets |
| 1,500 profile limit (Unlimited Edition) | 1,000 Permission Sets + groups |
Standard vs Custom Profiles
| Feature | Standard Profiles | Custom Profiles |
|---|---|---|
| Object permissions | Cannot reduce below standard | Fully configurable |
| FLS | Can restrict (since Spring ‘23) | Fully configurable |
| System permissions | Fixed | Configurable |
| Deletable | No | Yes (if no users assigned) |
| Editable | Limited | Full |
| Recommendation | Avoid for real implementations | Always use custom profiles |
Standard Profile Trap
Standard profiles (like “Standard User”) have built-in permissions that cannot be removed. You cannot, for example, remove Read access to Accounts from the Standard User profile. This makes standard profiles unsuitable for minimum access architectures. Always create custom profiles.
Permission Sets
Permission Sets add permissions on top of the Profile baseline. They are the primary mechanism for granting granular access in modern Salesforce architectures.
Permission Set Design Principles
- One concern per Permission Set — “Sales: Create Quotes” not “Sales User Everything”
- Name descriptively — include the functional area and the permission being granted
- Never duplicate Profile permissions — Permission Sets are additive
- Group logically — use Permission Set Groups to bundle related sets
- Document the purpose — every Permission Set should have a clear description
Permission Set Categories
| Category | Example | Granularity |
|---|---|---|
| Function-based | ”Sales: Create Opportunities” | Fine — one business function |
| Feature-based | ”Einstein Analytics User” | Medium — access to a platform feature |
| Role-based | ”Regional Manager Permissions” | Broad — use Permission Set Groups instead |
| Integration-based | ”API: Order Sync Service” | Fine — specific integration needs |
| Temporary | ”Q4 Promotion Campaign Access” | Time-limited (use session-based or assignment expiration) |
Permission Set Assignment
| Method | Use Case | Automation |
|---|---|---|
| Manual assignment | Ad hoc, small scale | None — admin assigns via Setup |
| Assignment via group | Role-based bulk assignment | Assign Permission Set Group to users |
| Flow-based assignment | Dynamic, event-driven | Flow assigns/removes based on criteria |
| Apex-based assignment | Integration-driven | Code assigns during user provisioning |
| Permission Set Assignment Expiration | Temporary access | Auto-expires after specified date |
Permission Set Groups
Permission Set Groups bundle multiple Permission Sets into a single assignable unit. They represent a “role” in the permission model.
Permission Set Group Architecture
flowchart TD
subgraph "Permission Set Group: Sales Manager"
PSG["Permission Set Group"]
PS1["PS: Read Accounts"]
PS2["PS: Read/Write Opportunities"]
PS3["PS: Read/Write Quotes"]
PS4["PS: Run Sales Reports"]
PS5["PS: View Forecasts"]
MPS["Muting PS: Block Delete Opp"]
end
PSG --> PS1
PSG --> PS2
PSG --> PS3
PSG --> PS4
PSG --> PS5
PSG -.->|"Mutes"| MPS
User["User with\nMinimum Access Profile"] --> PSG
style PSG fill:#1565c0,color:#fff
style MPS fill:#c62828,color:#fff
style User fill:#2e7d32,color:#fff
Muting Permission Sets
Muting Permission Sets remove specific permissions from a Permission Set Group without modifying the underlying Permission Sets. This is critical for reuse.
Example: The “Write Opportunities” Permission Set grants Create, Read, Edit, Delete on Opportunities. The Sales Manager group needs everything except Delete. Instead of creating a separate Permission Set, create a Muting Permission Set that blocks Delete.
| Without Muting | With Muting |
|---|---|
| Create “Write Opps No Delete” Permission Set | Reuse “Write Opps” Permission Set |
| Duplicate Permission Sets for slight variations | One muting set per group removes specific permissions |
| Permission Set sprawl | Clean, composable architecture |
Muting Permission Set Limitations
Muting Permission Sets can only mute permissions within their own Permission Set Group. They cannot mute permissions granted by the user’s Profile or by individually assigned Permission Sets. This reinforces the minimum access profile pattern — if the Profile grants a permission, muting cannot override it.
How Record Access and Object/Field Access Combine
A user must pass BOTH the record-level check AND the object/field-level check to access data. These two layers are evaluated independently and both must grant access.
flowchart TD
UserRequest["User requests\ndata access"] --> RecordCheck{"Record-Level Access\n(Sharing Model)"}
RecordCheck -->|"Can see the record?\n(OWD + Hierarchy +\nSharing Rules + etc.)"| ObjCheck{"Object-Level Access\n(Profile + Permission Sets)"}
RecordCheck -->|"No record access"| Denied1["Access Denied\n(Record not visible)"]
ObjCheck -->|"Has CRUD on object?"| FieldCheck{"Field-Level Security\n(Profile + Permission Sets)"}
ObjCheck -->|"No object permission"| Denied2["Access Denied\n(No object permission)"]
FieldCheck -->|"Field visible?"| Granted["Data Returned\n(Only visible fields)"]
FieldCheck -->|"Field hidden"| Partial["Record returned\nbut field stripped"]
style Granted fill:#2e7d32,color:#fff
style Denied1 fill:#c62828,color:#fff
style Denied2 fill:#c62828,color:#fff
style Partial fill:#e65100,color:#fff
CTA Board Framing
When presenting your security architecture, explicitly separate the two layers: “For record visibility, I use Private OWD with criteria-based sharing rules. For object and field access, I use a Minimum Access Profile with Permission Set Groups. These are independent — a user who can see a record via sharing still cannot see fields their FLS hides.”
Object Permissions (CRUD)
Object permissions control Create, Read, Edit, Delete (CRUD) plus two elevated permissions: View All and Modify All.
CRUD + View All / Modify All
| Permission | What It Does | Requires |
|---|---|---|
| Create | Insert new records | Read |
| Read | View records (subject to sharing) | Nothing |
| Edit | Update existing records | Read |
| Delete | Delete records | Read + Edit |
| View All | See ALL records regardless of sharing model | Read |
| Modify All | Edit/Delete ALL records + transfer ownership regardless of sharing | Read + Edit + Delete |
View All / Modify All vs System Admin
| Capability | View All | Modify All | System Admin |
|---|---|---|---|
| See all records (bypass sharing) | Yes | Yes | Yes |
| Edit all records | No | Yes | Yes |
| Delete all records | No | Yes | Yes |
| Transfer record ownership | No | Yes | Yes |
| Change sharing settings | No | No | Yes |
| Manage object metadata | No | No | Yes |
View All / Modify All Bypass Sharing
View All and Modify All bypass the entire sharing model — OWD, role hierarchy, sharing rules, teams, everything. Use these permissions sparingly and only when genuinely needed (e.g., data stewards, compliance officers, integration users). The CTA board will question any architecture that relies heavily on View All / Modify All.
Field-Level Security (FLS)
FLS controls which fields users can see and edit on an object, independent of object-level permissions.
FLS Settings
| Setting | User Can See | User Can Edit |
|---|---|---|
| Visible + Editable | Yes | Yes |
| Visible + Read Only | Yes | No |
| Hidden | No | No |
FLS vs Page Layouts
This is a critical distinction that CTA candidates must understand:
| Aspect | Field-Level Security | Page Layout |
|---|---|---|
| What it controls | Data access (API + UI) | UI presentation only |
| Security enforcement | Yes — enforced at API level | No — only affects page display |
| Can user see via API? | Only if FLS grants access | Always (if FLS allows) |
| Can user see in reports? | Only if FLS grants access | Yes (if FLS allows) |
| Assigned via | Profile or Permission Set | Profile + Record Type combination |
| True security boundary? | YES | NO |
Page Layouts Are Not Security
Removing a field from a page layout does NOT prevent users from accessing that field. They can still see it via reports, list views, API queries, and any custom UI. Only FLS controls true field-level access. This is a common mistake that the CTA board specifically tests for.
FLS Best Practices
- Default to hidden — only make fields visible when there is a business need
- Use Permission Sets for FLS — do not manage FLS on profiles (minimum access pattern)
- Audit FLS regularly — field visibility creeps over time
- Remember API access — FLS applies to API calls too; integrations need field access
- Test with different users — verify FLS enforcement in reports, list views, and API
Tab Visibility
Tab visibility controls whether an object’s tab appears in the app navigation.
| Setting | Behavior |
|---|---|
| Default On | Tab is visible by default |
| Default Off | Tab is available but hidden by default — user can add it |
| Tab Hidden | Tab is not available to the user at all |
Tab Visibility vs Object Access
Hiding a tab does NOT prevent access to the object’s records. Users can still access records via related lists, search, reports, and direct URLs. Tab visibility is a UI convenience, not a security control.
The Modern Permission Model
The recommended architecture for enterprise Salesforce combines all these elements:
flowchart TD
subgraph "Foundation"
MAP["Minimum Access Profile\n(Almost no permissions)"]
end
subgraph "Permission Layer"
PSG1["PSG: Sales Rep"]
PSG2["PSG: Sales Manager"]
PSG3["PSG: Service Agent"]
PSG4["PSG: Integration User"]
end
subgraph "Component Permission Sets"
PS1["PS: Read Accounts"]
PS2["PS: Write Opportunities"]
PS3["PS: Read Cases"]
PS4["PS: Write Cases"]
PS5["PS: API Access"]
PS6["PS: Run Reports"]
end
subgraph "Muting Layer"
M1["Mute: No Delete Opp"]
M2["Mute: No Export Data"]
end
MAP --> PSG1
MAP --> PSG2
MAP --> PSG3
MAP --> PSG4
PSG1 --> PS1
PSG1 --> PS2
PSG1 --> PS6
PSG2 --> PS1
PSG2 --> PS2
PSG2 --> PS6
PSG2 -.-> M1
PSG3 --> PS1
PSG3 --> PS3
PSG3 --> PS4
PSG3 --> PS6
PSG4 --> PS1
PSG4 --> PS5
PSG4 -.-> M2
style MAP fill:#c62828,color:#fff
style PSG1 fill:#1565c0,color:#fff
style PSG2 fill:#1565c0,color:#fff
style PSG3 fill:#1565c0,color:#fff
style PSG4 fill:#1565c0,color:#fff
Related Topics
- Sharing Model — record-level access works alongside object/field access
- Programmatic Security — enforcing FLS and CRUD in Apex code
- Portal Security — external user permission model
- Decision Guides — Profile vs Permission Set decision tree
- Security Best Practices — permission model anti-patterns
Sources
- Salesforce Help: Profiles
- Salesforce Help: Permission Sets
- Salesforce Help: Permission Set Groups
- Salesforce Help: Field-Level Security
- Salesforce Help: Muting Permission Sets
- Salesforce Architects: Permission Set Group Architecture