Skip to main content
One idea at a time

An invitation is a limited permission to join

An Acme admin invites Sam as a member. The invitation is not yet a membership. It is a temporary permission for a specific person to create that membership.

Taskboard records the workspace, invited email, intended role, token hash, and expiry. The email contains the raw token in its acceptance link. The invitation row stores only the verification hash, but the email job contains the complete link until its payload is removed. That job needs protected access and a retention policy.

Possession is necessary but not sufficientโ€‹

Sam signs in and verifies his email before accepting the invitation. The API checks that the authenticated account's verified email matches the invitation's email. Otherwise, a forwarded or exposed link could admit an unintended account.

The API also checks expiry and previous acceptance. A token that was valid yesterday may no longer be usable. The token's hash makes lookup possible without storing the bearer credential in plain text.

Acceptance creates a workspace membership with the invitation's intended role. The client must not override that role in its request. The admin's original invitation determined the grant.

Acceptance changes shared stateโ€‹

Two browser requests can submit the same token at nearly the same time. Both must not independently consume the invitation or create duplicate memberships.

A transaction coordinates invitation state and membership creation. A unique membership constraint supplies a final duplicate guard. If the workspace has a member limit, acceptance also needs coordination on the workspace so simultaneous acceptances cannot both take the final available slot.

The HTTP result should reflect the actual committed outcome. Sending an email before the invitation transaction commits can distribute a link that points to no usable invitation.

Taskboard records email work with the invitation so delivery can happen after commit through its background worker. SMTP failure then changes job state, rather than erasing the business record silently.

Tokens are secrets even without passwordsโ€‹

An invitation token grants a capability. Full URLs containing the token should not appear in request logs or analytics. Production acceptance links need HTTPS and a deliberate frontend origin.

A common mistake is using the workspace identifier as an invitation credential. That identifier appears throughout normal API routes and cannot represent a secret grant.

Can acceptance trust the role supplied by the invited user?

No. Acceptance uses the role recorded by the authorized inviter. Otherwise, a member invitation could be turned into an owner grant.

An invitation combines a limited secret with a stored policy. Acceptance validates both and commits the membership change atomically.

Read api/src/tenancy.ts Read api/src/jobs.ts