Unified invitations
Unified invitations let an administrator invite a person to one application while offering one or more eligible identity-provider routes, including local UserStore and federated providers. One route completes the invitation; the other routes become unusable.
Why unified invitations are needed
A legacy invitation marker is not enough for enterprise onboarding. Administrators need to know who was invited, for which tenant and application, which IDPs were permitted, whether the address or login name could change, which approvals and assignments were required, and whether the invitation expired, was cancelled, or was replaced.
The unified invitation is a central lifecycle record for those decisions. It prevents the same invitation from creating multiple identities, prevents email similarity from silently linking accounts, and keeps application or group assignments pending until enrollment is complete.
Choose an invitation design
| Requirement | Recommended choice |
|---|---|
| The address in the invitation is authoritative | Set AllowEmailChange to false. The user cannot redirect the invitation to another mailbox. |
| The user may have received the invitation at an alias or temporary address | Set AllowEmailChange to true. ProAuth requires proof of both the invited address and the replacement address. |
| The administrator assigns workforce login names | Supply LoginName and keep AllowLoginNameChange set to false. |
| The user chooses a local login name | Supply an initial reserved value and set AllowLoginNameChange to true. The replacement is reserved before it is accepted. |
| Either a corporate IDP or UserStore account is acceptable | Include both IDP types in EligibleIdpInstanceIds. The first successfully completed route wins atomically. |
| The invitation targets an existing ProAuth subject | Set IntendedProAuthUserId. ProAuth does not infer this relationship from an email address. |
| Regulated onboarding | Set RequiredApprovals to the required independent approval count and include the approved change reference in the surrounding administrative process. |
No email-based account linking
An email address can prove control of a mailbox. It does not prove that two provider identities belong to the same ProAuth subject. Use an explicitly targeted invitation or the identity replacement workflow instead of automatic email linking.
Lifecycle
The aggregate also records each route as Eligible, Selected, BootstrapInProgress, AwaitingApproval, Completed, Failed, Cancelled, or Superseded.
The following rules apply throughout the lifecycle:
- the invitation secret and route bootstrap secret have 256 bits of entropy and are stored only as hashes;
- expiry and state are checked again at every transition;
- route selection and completion use concurrency-protected transitions;
- only one route can win;
- a GET request does not consume or advance the invitation;
- reminders rotate the invitation secret, which invalidates an older link;
- cancellation and supersession release active reservations and invalidate secrets;
- ordinary application tokens are issued only after enrollment, approvals, and assignments complete.
Create an invitation
Use Management API v2:
POST /api/management/v2/unified-invitations
Content-Type: application/json{
"subscriptionId": "<subscription-id>",
"tenantId": "<tenant-id>",
"clientAppId": "<target-client-id>",
"emailAddress": "alex@example.com",
"allowEmailChange": false,
"loginName": "alex@example.com",
"allowLoginNameChange": false,
"eligibleIdpInstanceIds": ["<userstore-idp-id>", "<federated-idp-id>"],
"lifetimeHours": 168,
"policyFingerprint": "<approved-policy-fingerprint>",
"requiredApprovals": 0,
"authorizedClientAppIds": ["<additional-client-id>"],
"groupIds": ["<group-id>"]
}Command fields
| Field | Required | Valid values and effect |
|---|---|---|
SubscriptionId | Yes | Subscription that owns the intended ProAuth user. |
TenantId | Yes | Tenant in which redemption and assignments occur. |
ClientAppId | Yes | Application for which the invitation was issued. |
IntendedProAuthUserId | No | Explicit existing subject. If omitted, ProAuth stages a new inactive subject. |
EmailAddress | Yes | Valid invited email address. |
AllowEmailChange | No | false by default. When true, replacement requires dual proof. |
LoginName | No | Initial local login name. If omitted, UserStore bootstrap uses the email address. |
AllowLoginNameChange | No | false by default. When true, a new canonical login name must be reserved. |
EligibleIdpInstanceIds | Yes | One or more eligible UserStore or federated IDP instances. The snapshot is immutable. |
LifetimeHours | No | 1–2160; default 168 (7 days). |
PolicyFingerprint | Yes | Records the policy decision under which the invitation was issued. |
RequiredApprovals | No | 0–5; default 0. The requester cannot satisfy an independent approval requirement alone. |
AuthorizedClientAppIds | No | Client assignments applied only during successful finalization. |
GroupIds | No | Group memberships applied only during successful finalization. |
LifetimeHours, identifier mutability, approvals, routes, and assignments are properties of an invitation. They are not UserStore IDP options.
UserStore bootstrap
When the user selects a UserStore route, ProAuth creates a provisional local user that cannot authenticate normally. The route then guides the user through the permitted credential enrollment:
- set an initial password when password creation is allowed;
- register a login passkey when passkeys are enabled;
- satisfy the effective recovery-readiness requirements;
- accept the immutable identifiers or complete an allowed identifier change.
Password and passkey policy are evaluated by the same server services used during normal credential management. Completing credential enrollment does not by itself activate the account. Central approval and assignment orchestration must still succeed.
Mutable identifiers
Changing the email address
When AllowEmailChange is true, ProAuth starts a 30-minute identifier-change attempt and sends separate proof codes to:
- the original invited address; and
- the proposed replacement address.
Both codes must be valid for the same invitation, route, attempt, and security state. Five failed proof attempts terminate the change attempt and release the pending reservation. A successful change transfers the reservation and updates the provisional UserStore user.
This dual proof prevents a forwarded or stolen invitation from being redirected to an attacker-controlled mailbox without the original recipient's participation.
Changing the login name
When AllowLoginNameChange is true, ProAuth canonicalizes and reserves the proposed login name before accepting it. A duplicate or quarantined canonical value fails closed. No database collation or case-sensitive race decides the winner.
Reminders, cancellation, and reissue
| Operation | Endpoint | Behavior |
|---|---|---|
| Read | GET /api/management/v2/unified-invitations/{id} | Returns lifecycle, route, approval, assignment, reminder, and supersession state. |
| Remind | POST /api/management/v2/unified-invitations/{id}/remind | Allowed at most twice, at least 24 hours apart. Rotates the invitation secret and queues durable delivery. |
| Cancel | POST /api/management/v2/unified-invitations/{id}/cancel | Requires a reason. Invalidates secrets, releases reservations, and cancels pending routes and assignments. |
| Reissue | POST /api/management/v2/unified-invitations/{id}/reissue | Creates a replacement for 1–2160 hours and supersedes the source. Fails once route bootstrap has started. |
| Approve | POST /api/management/v2/unified-invitations/{id}/approvals | Requires ProAuthUser.ApproveInvitation; records an independent actor. |
Delivery is durable. The invitation link and recipient are stored inside a protected outbox payload, and the built-in job scheduler checks for pending delivery every minute. Delivery uses leases and retries. The same maintenance cycle processes expired history, invitation expiry and ready invitations; a failure in one operation does not prevent the others from running. Management read APIs never return the bearer secret.
Deleting an invited user or related configuration
Deleting the intended ProAuth user, an eligible identity provider (including a UserStore), target client application, tenant, subscription or customer also retires the affected unified invitations. You do not need to cancel each invitation first. Existing deletion prerequisites still apply: remove dependent resources (such as users, providers, clients and tenants) before deleting their parent subscription or customer. Retained invitation history does not add another prerequisite.
- Active invitations become Cancelled. Invitations already redeemed, cancelled, expired, superseded or failed keep their final outcome.
- Invitation links and bootstrap proofs stop working. Pending deliveries, identifier reservations, approvals, routes and assignment instructions are removed. An archived invitation cannot be reminded, approved, cancelled again or reissued.
- A minimal history record remains: invitation ID, subscription/tenant/client scope IDs, lifecycle timestamps, final outcome, archive time, retention deadline and a fixed deletion reason. Email addresses, login names, intended-user references, provider identities, actor identifiers, policy fingerprints and secret/proof material are removed from the invitation record.
The v2 read endpoint returns this redacted record while its retention period is valid. ArchivedOn identifies history; HistoryExpiresOn is its deadline, and CancellationReason identifies the deleted resource type. Scope IDs can refer to deleted resources and do not keep those resources alive. Access still requires authorization. After the deadline, reads return not found; the background worker physically removes expired history in batches.
This cleanup concerns invitation data. It does not erase previously delivered email, separately retained audit logs, backups or independently managed provider accounts. In particular, an unfinished provisional UserStore account is a separate account record; review it using the store's account-management procedures. Removing an invitation does not activate it.
Administrator procedure
- Confirm the target and whether any invitation journey is currently being completed. Deleting a shared provider or a parent scope affects every invitation that depends on it, including invitations offering other eligible providers.
- Delete the resource using its management API or an available AdminApp deletion action. The ProAuth Users view currently exposes editing and deactivation; use the management API to delete a central ProAuth user. Successful deletion archives affected invitations in the same transaction.
- If the service returns 409 Conflict because delivery, provisioning or activation is in progress, allow that operation to finish and refresh before retrying. Investigate a repeatedly stuck operation; cancelling an invitation is not a way to bypass in-flight work.
- For a new onboarding attempt after deletion, create a fresh invitation for valid resources. History cannot restore a deleted user, assignments or secret.
We recommend keeping a short history window that covers your support and incident-review needs, while managing audit-log and backup retention separately. Cancelling an invitation without deleting a related resource continues to use the ordinary cancellation workflow; it does not start this deletion-history retention period.
Configure history retention
The default is 90 days from archival. Configure ProAuthRoot:InvitationHistoryRetentionDays to a whole number from 1 to 3650. Invalid values prevent application startup. Use the same value on every serving instance. The deadline is recorded when deletion occurs; changing the setting does not shorten or extend records already archived.
For containers, set:
ProAuthRoot__InvitationHistoryRetentionDays=30For Helm deployments:
appsettings:
proauthroot:
invitationhistoryretentiondays: 30An unset Helm value uses the application default. History is unavailable through the API as soon as its deadline passes, although physical removal can take longer if the worker is stopped or a purge backlog exists.
Assignment orchestration
Authorized-client and group assignments are validated when the invitation is created and remain Pending until the winning route is ready. Finalization applies each assignment idempotently. An assignment failure keeps the invitation from becoming Redeemed and records a privacy-safe failure code for operations.
This ordering avoids granting access to a provisional or partially enrolled identity.
Mixed federated and UserStore invitations
It is safe to offer both route types because the central invitation, not the provider, chooses the subject and consumes the winning route. A federated callback must match its selected IDP, issuer, subject, route secret, invitation, and intended user. A UserStore completion must match its provisional user and route.
If an intended subject already has a different active identity, the invitation does not silently attach another identity. Use the governed identity replacement workflow.
Operations and troubleshooting
Monitor these conditions:
- invitations approaching expiry;
- repeated identifier-proof failures;
- reminder delivery failures or dead letters;
- assignment failures;
- invitations waiting for approval;
- route conflicts and replay rejections;
- provisional UserStore users that never complete bootstrap.
For legacy marker migration, see UserStore migration and activation.