How Access Control Works

Understanding DoorFlow's permission system in 5 minutes

5 mins
Beginner

Quick explanation of how DoorFlow decides who can access which doors.

The Permission Chain

Person → Credential → Group → Role → Channel

All 4 must be true for access to be granted:

  1. Person has a Credential (card/PIN/mobile)
  2. Person belongs to a Group
  3. Group has a Role granting access
  4. Role includes the specific Channel (door)

If ANY link is missing, access is denied.

Real-World Example

Jane wants to access the Front Door:

graph TD Jane[Jane - Person] Cred1[Card #1234567890] Group1[Employees Group] Role1[Standard Access Role] Doors1[Front Door, Office, Kitchen] Result1[Access Granted ✓] Jane -->|Has| Cred1 Jane -->|Belongs to| Group1 Group1 -->|Has| Role1 Role1 -->|Grants access to| Doors1 Doors1 -->|Front Door matches| Result1 classDef success fill:#D1FAE5,stroke:#10B981,stroke-width:2px classDef person fill:#E0F2FE,stroke:#0EA5E9,stroke-width:2px class Result1 success class Jane person

Result: Jane scans card → Access Granted

Bob tries to access the Server Room:

graph TD Bob[Bob - Person] Cred2[Card #9876543210] Group2[Employees Group] Role2[Standard Access Role] Doors2[Front Door, Office, Kitchen] ServerRoom[Server Room] Result2[Access Denied ✗] Bob -->|Has| Cred2 Bob -->|Belongs to| Group2 Group2 -->|Has| Role2 Role2 -->|Grants access to| Doors2 ServerRoom -.->|NOT included in role| Result2 classDef denied fill:#FEE2E2,stroke:#EF4444,stroke-width:2px classDef person fill:#E0F2FE,stroke:#0EA5E9,stroke-width:2px class Result2 denied class Bob person

Result: Bob scans card → Access Denied

Permanent vs Temporary Access

Permanent Access (via Groups)

Use for: Employees, long-term contractors

How it works

Assign person to group
Group has role(s) defining channel access
Access remains until person is removed from group

Example:

bash
# Create employee
POST /api/3/people
{"first_name":"Jane","group_ids":[1]}  # Assign to "Employees" group

# Issue credential
POST /api/3/people/12345/credentials
{"person_credential":{"credential_type_id":5,"value":"1234567890"}}

# Done! Jane has permanent access to all doors the "Employees" group can access

Temporary Access (via Reservations)

Use for: Visitors, one-time access, after-hours

How it works

Create reservation with start/end times
Specify which channels person can access
Access auto-expires after end time

Example:

bash
# Create visitor
POST /api/3/people
{"first_name":"Visitor","group_ids":[2]}  # "Visitors" group

# Issue temp PIN
POST /api/3/people/67890/credentials
{"person_credential":{"credential_type_id":6,"value":"******"}}

# Grant time-limited access
POST /api/3/reservations
{
  "person_id": 67890,
  "channel_ids": [1340],  # Just the lobby
  "start_time": "2024-01-15T09:00:00Z",
  "end_time": "2024-01-15T17:00:00Z"
}

# Visitor's PIN stops working after 5 PM automatically

Multiple Groups = Additive Access

People can belong to multiple groups. Access is additive (more groups = more doors).

Example:

Jane belongs to:
  - "Employees" group → Front Door, Office, Kitchen
  - "IT Team" group → Server Room, Network Closet

Total access: Front Door, Office, Kitchen, Server Room, Network Closet

Why Access Might Be Denied

Common reasons access fails:

Reason Event Code Fix
Person disabled 21 Enable person: PUT /people/{id} with {"enabled":true}
Credential disabled 22 Enable credential
No permission for door 23 Add person to group with access, or create reservation
Outside allowed hours 24 Adjust role schedule or create reservation
Invalid credential 25 Check credential format/value
Reservation expired 26 Extend or create new reservation

Check Events API to see exact reason:

bash
GET /api/3/events?person_id=12345&event_code=20&event_code=21&event_code=22&event_code=23

Troubleshooting Access Issues

Person created but can't access doors:

Wrong:

bash
# Only created person - missing credential and group!
POST /api/3/people
{"first_name":"Jane","email":"jane@example.com"}

Correct:

bash
# 1. Create with group assignment
POST /api/3/people
{"first_name":"Jane","email":"jane@example.com","group_ids":[1]}

# 2. Issue credential
POST /api/3/people/12345/credentials
{"person_credential":{"credential_type_id":5,"value":"1234567890"}}

Need to check if someone has access to a specific door:

bash
# 1. Get person's groups
GET /api/3/people/12345
# Returns: "group_ids": [1, 5]

# 2. Check if those groups have roles granting access
GET /api/3/roles
# Look for roles where:
#   - group_ids includes [1 or 5]
#   - channel_ids includes the target door

Access Hierarchy Diagram

graph TB Account[Account] Sites[Sites/Buildings] Channels[Channels/Doors] Roles[Roles/Permissions] Groups[Groups/Collections] People[People/Individuals] Credentials[Credentials/Access Tokens] Reservations[Reservations] Account --> Sites Sites --> Channels Roles -->|grants access to| Channels Groups -->|assigned to| Roles People -->|member of| Groups People --> Credentials Reservations -.->|direct time-limited access| Channels classDef physical fill:#E0F2FE,stroke:#0EA5E9,stroke-width:2px classDef logical fill:#FEF3C7,stroke:#F59E0B,stroke-width:2px classDef access fill:#D1FAE5,stroke:#10B981,stroke-width:2px class Account,Sites,Channels physical class Roles,Groups logical class People,Credentials,Reservations access

Key Takeaways

To grant permanent access

Create person
Assign to group (group already has role)
Issue credential

To grant temporary access

Create person
Issue credential
Create reservation with time limits

To revoke access

Fast: Disable person (enabled: false)
Selective: Disable specific credentials
Permanent: Remove from groups or delete

Access is additive

Multiple groups = access to all their doors
Reservations + group access = combined permissions

Common mistake: Creating a person without credentials or groups won't work!