An application may grant access to alex@example.test and appear to work correctly for years. Then Alex changes address, leaves the organization, or the old address is assigned to someone else. If the authorization system treats that address as the identity itself, access can follow the label instead of the person or service that was originally approved.

This is an identity-binding problem. Authorization needs to answer not only what may this requester do? but also which principal does this grant actually belong to? A principal is the security identity that receives permissions, such as a user account or service account.

The defensive design is to bind grants to a stable principal identifier and treat names, email addresses, and other editable attributes as descriptive data. This article explains why that distinction matters, how to model it, how to handle renames and account replacement, and where stable identifiers do not solve the whole authorization problem.

Separate identity from its labels

Start with a small mental model. Suppose an application stores this grant:

project: 731
member: alex@example.test
role: editor

The record looks readable, but it leaves an important question unanswered: what does alex@example.test mean?

It might mean the account currently carrying that address. It might mean the person who carried it when the grant was created. Those are different policies.

A stronger model separates the security identity from the attributes used to describe it:

principal ID: usr_7f2c
email:        alex@example.test
display name: Alex

The access grant then stores the principal ID:

project:      731
principal ID: usr_7f2c
role:         editor

The email address can change without changing which principal owns the grant. Conversely, assigning the old email address to another account does not transfer the grant, because the new account has a different principal ID.

The identifier does not need to be meaningful to a human. In fact, a value whose only job is identity is often easier to reason about because application code is less tempted to reinterpret it as an email address, username, or business label.

The threat is unintended transfer of authority

The main threat is not that an attacker guesses a principal ID. The problem is that a mutable or reusable attribute can change its referent while an old authorization record remains in place.

Consider a team application with this sequence:

1. account A owns alex@example.test
2. project 731 grants editor access to alex@example.test
3. account A changes to alex.new@example.test
4. alex@example.test later belongs to account B
5. authorization looks up grants by current email address

At step 5, account B may inherit a grant that was intended for account A. Nothing about the grant itself changed. The meaning of the value used as its identity changed underneath it.

A stable principal ID breaks that chain:

account A -> usr_7f2c -> editor grant
account B -> usr_91aa -> no editor grant

Changing an account attribute does not rewrite the subject of the grant. Reusing an old attribute does not make a different principal equal to the original one.

This control reduces authorization errors caused by renames, recycled identifiers, attribute reassignment, and ambiguous identity matching. It does not protect an account whose authenticators are compromised, and it does not make an overly broad role appropriate.

Choose identifiers for identity, not presentation

A useful principal identifier has a narrow contract: it identifies one security principal within the scope where authorization decisions are made.

For an application-managed user table, that is commonly an internal account ID generated when the account is created. The exact representation is less important than its lifecycle semantics. A database-generated integer, UUID, or another opaque unique value can all work if the application treats the value consistently.

Three properties matter more than appearance.

First, the identifier should not change merely because editable profile data changes. A user changing an email address or display name should normally remain the same principal.

Second, an identifier for a deleted principal should not later be assigned to a different principal. Reuse can turn old references into authority for a new account.

Third, every component that interprets the identifier must agree on its namespace. The string 123 is not globally meaningful if one service means customer 123 and another means administrator 123.

This is why copying a username into a field called principal_id does not solve the problem. The security property comes from the identifier’s lifecycle and namespace, not from the column name.

Resolve human-friendly attributes before creating the grant

People still need to invite colleagues by email address or find accounts by username. The goal is not to remove human-friendly identifiers from the product. The goal is to stop using them as the durable authorization binding.

A simple invitation flow can separate lookup from storage:

1. administrator enters alex@example.test
2. application resolves it to principal usr_7f2c
3. administrator confirms the intended account
4. application stores the grant for usr_7f2c

After step 4, authorization should evaluate the stable principal ID. The email address may remain in audit or display data as a snapshot for human context, but it is not the value that determines who receives access.

This separation also makes ambiguity visible. If an email address has not yet been verified for an account, or the product allows several accounts to share the same contact address, the application should not silently pretend that the address uniquely identifies a principal. The enrollment or invitation design needs an explicit way to establish which account receives the grant.

For systems that intentionally grant authority to whoever controls a particular address in the future, that is a different policy. Model it explicitly rather than accidentally obtaining that behavior from an email-based join.

Keep identity linking separate from authorization

Applications often accept identities from another system, such as an organization identity provider. The same principle still applies, but the trust boundary moves.

Do not assume that a familiar attribute from the external identity is a permanent account key. Email addresses, login names, and group labels may change according to the provider’s lifecycle rules.

Instead, establish an explicit mapping from the external identity’s stable identifier, within its documented namespace, to the application’s principal. The application can then authorize its own principal ID:

external identity
      |
      v
verified identity mapping
      |
      v
application principal ID
      |
      v
authorization grants

The exact external identifier is protocol- and provider-dependent, so its stability and uniqueness must come from that system’s documented contract rather than assumption. If two identity providers can issue the same-looking identifier, the issuer or identity namespace must be part of the mapping.

This matters during migrations. Changing identity providers is not merely a string replacement if the new provider uses a different identity namespace. The migration needs a controlled process for proving which new identity corresponds to each existing application principal.

Treat account merging as an authority-changing operation

Stable IDs make ordinary profile changes safer, but they also reveal operations that deserve special handling.

Suppose a product discovers that usr_7f2c and usr_91aa belong to the same human and offers to merge the accounts. Combining their permissions is not just data cleanup. It can produce a principal with the union of both accounts’ authority.

Before a merge, imagine:

usr_7f2c -> billing project
usr_91aa -> deployment project

After a naive merge:

merged principal -> billing project + deployment project

That result may be intended, but it should be an explicit security decision. Account linking, merging, splitting, and identity-provider migration can all change which authenticator can reach existing grants.

For sensitive systems, these operations deserve fresh authorization, clear audit records, and a recovery plan. The stable identifier prevents accidental transfer through ordinary attribute changes; it should not hide deliberate identity reassignment behind an apparently harmless profile update.

Define deletion and recreation semantics

Deletion creates another boundary condition. If a principal is removed, what happens to grants that reference it?

Two designs are common. The application can delete or revoke the grants as part of account removal, or it can retain historical grant records while marking the principal inactive. Either approach can be valid depending on audit and recovery requirements.

What matters is that a newly created account does not become the same principal merely because it receives the same email address, username, employee number, or other recycled attribute.

For example:

old account: usr_7f2c, alex@example.test
new account: usr_c314, alex@example.test

The new account may need fresh approval before receiving the old account’s project access. If restoration of a deleted account is supported, define whether restoration revives the original principal and grants or creates a new principal that requires reauthorization. That choice affects both security and user expectations, so it should be intentional and testable.

Avoid reconstructing identity from attributes at request time

Even with stable IDs in the database, an application can reintroduce the problem in request handling.

A fragile authorization path looks conceptually like this:

request email -> find grants whose email matches -> allow

A stronger path is:

authenticated session -> principal ID -> evaluate that principal's grants

The authentication layer establishes which principal the request represents. The authorization layer consumes that established identity instead of searching for a principal again from mutable request attributes.

This also clarifies the trust boundary. An email address supplied in a request body is input. It is not evidence that the requester owns that identity. Even a verified email stored on the authenticated account is normally an attribute of the principal, not a replacement for the principal ID in every authorization query.

Where policy genuinely depends on an attribute, such as membership in a verified organization, make that dependency explicit. Then define how quickly changes to the attribute must affect access and which system is authoritative for it. Attribute-based authorization is legitimate; accidental identity-by-attribute is the problem.

Test lifecycle changes, not only successful access

A basic authorization test often creates a user, grants access, and verifies that the user can reach the resource. That confirms the happy path but misses the identity-binding failure.

Add lifecycle tests that exercise the meaning of the binding:

grant access to principal A
change A's email
assert A still has the intended grant

create principal B with A's former email
assert B does not inherit A's grant

delete A and create a new account with the same labels
assert the new principal has no old grant unless policy explicitly restores it

If the system integrates with an external identity provider, test identity-link changes and migration paths as well. The expected result should be stated in terms of principals and grants, not only visible usernames.

Operationally, audit records should include the stable principal ID plus useful human-readable context. A log entry containing only usr_7f2c is difficult for an investigator to read, while a log entry containing only an email address can become ambiguous after a rename. Recording both the durable identity and an event-time display snapshot supports both purposes.

Know what stable identifiers do not solve

A stable identifier gives authorization records a durable subject. It does not establish that the current requester is genuinely that subject. Authentication and session security still have to do that work.

It also does not decide which permissions the principal should receive. Least privilege, object-level authorization, approval for sensitive grants, timely revocation, and authorization at the point of use remain separate controls.

Stable identifiers can themselves be mishandled. If an application accepts a client-supplied principal ID and authorizes it without binding that value to the authenticated session, an attacker may simply name another principal. The identifier is a reference, not proof of authority.

Finally, some business policies are intentionally attribute-based. A rule such as “current members of the incident-response group may view this dashboard” is meant to change when group membership changes. In that case, freezing the decision to individual principal IDs could defeat the intended policy. The important design step is to distinguish a durable identity binding from a policy that deliberately follows changing attributes.

Make the authorization subject explicit

When a grant is meant for a particular account or service, store the grant against a stable, non-reused principal identifier. Use email addresses, usernames, and display names for lookup and presentation unless their changing meaning is explicitly part of the policy.

Then test the lifecycle events that challenge that assumption: rename the account, recycle an old label, delete and recreate the account, and change external identity mappings. The expected result should remain clear about which principal owns the authority.

That small modeling choice removes a class of subtle access-transfer bugs. More importantly, it forces the system to answer a precise security question: is this permission attached to this principal, or merely to whatever currently carries this label?