Surflet

Access Control

A detailed guide to the 6 access control modes

Surflet provides 6 access control modes to govern who can view and interact with a page. Each page can have its own independently configured access policy.

public — Open Access

Anyone with the link can access the page. Suitable for internal announcements and non-sensitive information.

access = surflet.Access.public()
access.public()

Payload structure:

{
  "access": {
    "mode": "public"
  }
}

Note: Public pages still require a valid page URL to access and are not indexed by search engines.

authenticated — Identity Verification

Only users with specified identities can access the page. Users verify their identity via Magic Link or SSO.

access = surflet.Access.authenticated(
    emails=["[email protected]", "[email protected]"],
)
access.authenticated({
  emails: ['[email protected]', '[email protected]'],
})

Payload structure:

{
  "access": {
    "mode": "authenticated",
    "allowed_identities": [
      {"type": "email", "value": "[email protected]"},
      {"type": "email", "value": "[email protected]"}
    ]
  }
}

Supported identity types:

TypeDescriptionExample
emailEmail address[email protected]
domainEmail domain (organization-level)company.com
groupUser groupengineering
roleRoleadmin
# Organization-level access — anyone in the company can view
access = surflet.Access.authenticated(
    identities=[
        {"type": "domain", "value": "company.com"},
    ],
)

# Mixed mode — specific emails + a specific group
access = surflet.Access.authenticated(
    identities=[
        {"type": "email", "value": "[email protected]"},
        {"type": "group", "value": "finance-team"},
    ],
)

The page can only be viewed once and self-destructs after reading. Ideal for transmitting sensitive information.

access = surflet.Access.one_time(
    burn_after=300,  # destroy 300 seconds (5 minutes) after viewing
)
access.oneTime({ burnAfter: 300 })

Payload structure:

{
  "access": {
    "mode": "one_time",
    "one_time_options": {
      "burn_after_seconds": 300
    }
  }
}

Behavior:

  • The countdown starts when the page is first opened
  • After burn_after seconds, the page content is permanently deleted
  • If burn_after is not set, the page becomes inaccessible immediately after closing
  • All access activity is recorded in the audit log

view_limited — View-Count Limit

Limits the total number of times a page can be viewed.

access = surflet.Access.view_limited(max_views=5)
access.viewLimited({ maxViews: 5 })

Payload structure:

{
  "access": {
    "mode": "view_limited",
    "view_limit": 5
  }
}

The counter increments by 1 each time the page loads. Once the limit is reached, the page is no longer accessible. Useful for restricting how widely information spreads.

time_limited — Time-Limited Access

The page automatically expires after a specified time.

access = surflet.Access.time_limited(
    expires_at="2026-04-01T00:00:00Z",
)
access.timeLimited({ expiresAt: '2026-04-01T00:00:00Z' })

Payload structure:

{
  "access": {
    "mode": "time_limited",
    "expires_at": "2026-04-01T00:00:00Z"
  }
}

After expiry, the page automatically transitions to expired status and becomes read-only. You can renew it using the renew API.

# Renew an expired page
client.renew_page("pg_xxx", expires_at="2026-05-01T00:00:00Z")

password — Password Protection

Users must enter a password to access the page.

access = surflet.Access.password(
    password_hash="sha256:a1b2c3d4...",
)
access.password({ passwordHash: 'sha256:a1b2c3d4...' })

Payload structure:

{
  "access": {
    "mode": "password",
    "password_hash": "sha256:a1b2c3d4..."
  }
}

Security note: Always transmit the hashed password, never the plaintext. Use SHA-256, formatted as sha256:<hex-encoded-hash>.

Combining with Approval Chains

Access control can be combined with approval chains. For example, an approval page accessible only to designated approvers:

page = client.publish(
    title="High-Value Refund Approval",
    page_type="approval",
    blocks=[...],
    actions=[
        surflet.Action("act_approve", "Approve", style="primary"),
        surflet.Action("act_reject", "Reject", style="danger"),
    ],
    access=surflet.Access.authenticated(
        emails=["[email protected]", "[email protected]"],
    ),
    approval_chain={
        "mode": "sequential",
        "steps": [
            {
                "step_id": "step_manager",
                "assignees": [{"type": "email", "value": "[email protected]"}],
                "policy": {"type": "any"},
            },
            {
                "step_id": "step_cfo",
                "assignees": [{"type": "email", "value": "[email protected]"}],
                "policy": {"type": "any"},
            },
        ],
    },
)

Default Behavior

If access is not specified when publishing, the default behavior is:

  • The page gets a unique random URL (not guessable)
  • Anyone with the URL can access it
  • Equivalent to public mode