Concepts
This page explains the model behind the API you integrate with. You do not need it to run the quickstart, but it explains why the values you receive look the way they do.
Account and persona
An account is the one real login: credentials, passkeys, MFA, recovery and verified contacts live here. An account can present personas to different services — for example a professional persona, a personal persona, or an anonymous one.
At consent the user chooses which persona to present to your RP. Your RP only ever sees that persona's projection: its PPID and the claims it shares. The account and the other personas stay invisible to you.
Consequences:
- One account can return to your RP as different personas. Those are different
subvalues. - Changing an attribute (an email, a phone number, a picture) never changes the PPID.
- The user can revoke your RP's access without deleting their account.
The PPID (sub)
TrustNet derives sub as a keyed hash over the RP's tenant and the chosen
persona:
sub = HMAC-SHA-256(salt, "trustnet-ppid-tenant-v1" ‖ tenant ‖ persona)
The result is a 43-character base64url string. The salt is held only by TrustNet, and the derivation runs only in TrustNet's backend.
Properties:
| Property | Guarantee |
|---|---|
| Stability | The same persona at the same tenant always yields the same sub, forever. |
| Cross-RP unlinkability | A different tenant yields a different sub for the same persona. |
| Cross-persona unlinkability | A different persona yields a different sub at the same RP. |
| No reverse mapping | The PPID is one-way and cannot be traced back to an account or persona by your RP. |
Use sub as your local user key. Do not expect it to match anything you see
from another identity provider or from another TrustNet tenant.
Tenant (the sector)
A tenant groups related RPs owned by one organization. It is the sector input to the PPID, which means:
- RPs in the same tenant share a
subper persona. - RPs in different tenants never share a
subfor the same persona.
Choose the tenant boundary deliberately. Put products that should recognize the same user together; keep unrelated brands or businesses in separate tenants.
The tenant is immutable for an RP: an RP never moves between tenants. A redirect host change does not re-derive PPIDs, because the sector is the tenant, not the hostname.
Consent
The user sees one consent screen that combines persona selection with the claim disclosure:
- the RP's name and logo;
- the persona being presented;
- each requested claim with the reason the RP supplied at registration;
- what is shared and what is not.
The user approves or denies. On approval, TrustNet issues tokens whose sub is
that persona's PPID and whose claims are exactly the approved set.
Consent behaviours you may encounter:
- First connection or claim escalation — full review is always shown.
- Remembered decision — a repeat request can render a read-only access-proof view and continue after a short countdown. The user can still choose to review or switch persona.
prompt=consent— forces full review even when a remembered decision exists.prompt=login— concerns the login half only; it does not by itself force a new consent review.prompt=select_account— TrustNet implements persona selection on the consent screen (there is no separate login persona picker).- Denial — the callback carries
error=access_denied. No tokens are issued.
A remembered decision is not a new consent grant. It reuses the prior approval until the user changes persona or revokes access.
Scopes and claims
TrustNet separates two things that standard OIDC commonly mixes:
- Scopes are protocol capabilities.
openidis required.offline_accessrequests a refresh token and ongoing access, which the consent screen discloses separately. - Claims are the user data. You declare the claims your RP may request at
registration, each with a reason, and request them per transaction with the
standard
claimsparameter.
A claim you did not declare at registration is never disclosed. A claim you declare but the user does not approve is omitted. A claim the chosen persona does not hold is omitted.
Requestable claims
| Category | Claims |
|---|---|
| Profile | name, given_name, family_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale |
| Contact | email, phone_number |
| Derived | email_verified, phone_number_verified, over_18 |
Notes:
pictureis a short-lived signed URL, not a raw file reference.email_verifiedandphone_number_verifiedare computed from the account's verified contact state; they are not stored attributes.over_18is derived frombirthdate.addressis not currently requestable (it is a structured object, not a flat scalar).subis always present and is not a declared claim.
Older integrations may still use the legacy profile, email and phone
scopes; new registrations should declare claims instead.
Tokens and sessions
| Item | Lifetime | Notes |
|---|---|---|
| Authorization code | 10 minutes | Single use. |
| Login/consent challenge | 30 minutes | The user must finish the flow inside this window. |
| Access token | 30 minutes | Opaque. Use it at UserInfo or the machine plane. |
| ID token | 30 minutes | Signed JWT. Validate it before trusting any value. |
| Refresh token | 30 days | Issued only when offline_access is granted. |
The access token is the key to your RP's consented access:
- it is opaque; do not parse it, and never use it as a JWT;
- it stops working when the user revokes access (the refresh token dies immediately as well);
- the machine plane authenticates it server-to-server; browser cookies are ignored there.
Two planes
| Plane | Who calls it | Authentication |
|---|---|---|
OIDC provider (id.trustnet.app) |
Browser redirects and your backend | Standard OIDC; client secret at the token endpoint |
RP machine plane (rp.trustnet.app/api/rp/v1) |
Your backend | Authorization: Bearer <access token> |
RP portal (me.trustnet.app) |
Your organization's staff in a browser | Normal account session + AAL2 step-up |
The portal is for managing the RP. The machine plane is for reading consented user data. They have deliberately separate authentication paths; do not mix them.