Last1 ID Architecture Bible
Single source of truth for everything built. Update this file when adding schema, endpoints, or architectural decisions.
1. Domain and Product Model
| Rule |
Value |
| Canonical domain |
https://last1.id |
| Last1 ID vs last1.app |
Independent; last1.app is a client |
| Users create in MVP |
Identities, credentials, consent — not apps |
| Integration point |
Last1 ID is the identity authority for the ecosystem |
Client Apps
- last1.app — separate product; integrates with Last1 ID
- RadioCheck
- MATR iOS
- MATR Biz
- RealOutcomes
2. DID Architecture
Method
did:web — resolves to HTTPS URLs on last1.id. No blockchain. Pragmatic standard for organizations hosting their own identifiers.
| Principal |
Format |
Example |
| Identity (user) |
did:web:last1.id:identities:<uuid> |
did:web:last1.id:identities:a1b2c3d4-... |
| Issuer |
did:web:last1.id:issuers:<uuid> |
did:web:last1.id:issuers:e5f6g7h8-... |
| App client |
did:web:last1.id:apps:<app_id> |
did:web:last1.id:apps:last1 |
DID Resolution (did:web spec)
| DID |
Resolves to |
did:web:last1.id |
GET https://last1.id/.well-known/did.json |
did:web:last1.id:issuers:<uuid> |
GET https://last1.id/issuers/<uuid>/did.json |
did:web:last1.id:identities:<uuid> |
GET https://last1.id/identities/<uuid>/did.json |
DID Document Structure (Issuers)
{
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/jwk/v1"],
"id": "did:web:last1.id:issuers:<uuid>",
"verificationMethod": [{
"id": "did:web:last1.id:issuers:<uuid>#key-1",
"type": "JsonWebKey",
"controller": "did:web:last1.id:issuers:<uuid>",
"publicKeyJwk": { "kty": "OKP", "crv": "Ed25519", "x": "..." }
}],
"assertionMethod": ["did:web:last1.id:issuers:<uuid>#key-1"],
"authentication": ["did:web:last1.id:issuers:<uuid>#key-1"]
}
3. Verifiable Credentials
VC Data Model (W3C 2.0-aligned)
@context: https://www.w3.org/ns/credentials/v2
type: ["VerifiableCredential", "<CredentialType>"]
id: urn:uuid:<credential-id>
issuer: issuer DID
validFrom: issued_at
validUntil: expires_at (optional)
credentialSubject.id: subject DID
proof: DataIntegrityProof (eddsa-jcs-2022)
Credential Types
| Internal Type |
VC Type |
| email_verified |
EmailVerificationCredential |
| phone_verified |
PhoneVerificationCredential |
| human_verified |
HumanVerificationCredential |
| identity_profile_completed |
IdentityProfileCredential |
| veteran_verified |
VeteranVerificationCredential |
| matr_cohort_member |
MatrCohortMemberCredential |
| matr_trust_program_completed |
MatrTrustProgramCredential |
| matr_facilitator_confirmed |
MatrFacilitatorCredential |
| radiocheck_participant |
RadioCheckParticipantCredential |
| beneficiary_enrolled |
BeneficiaryEnrolledCredential |
| provider_verified |
ProviderVerifiedCredential |
Signing
- Algorithm: Ed25519
- Proof type: DataIntegrityProof, cryptosuite eddsa-jcs-2022
- Canonicalization: Sorted-key JSON
- Private keys: Encrypted at rest (AES-256-GCM) with
CREDENTIAL_SIGNING_KEY
Credential Status
active — valid and usable
revoked — status column or revoked_at set
expired — expires_at in the past
suspended — status column
4. Schema
Core Tables
| Table |
Purpose |
| identities |
User identity records; includes did |
| linked_auth_providers |
External auth (Google, Microsoft, IdMe, email) |
| app_clients |
OAuth app clients; includes did |
| consent_grants |
User consent for app access |
| credential_issuers |
Issuers; includes did, allowed_credential_types, trust_level |
| credentials |
User credentials; includes signature, credential_vc |
| issuer_keys |
Ed25519 key pairs per issuer (public_key, private_key_encrypted) |
| trust_events |
Append-only trust-building events |
| reputation_snapshots |
Portable trust summaries |
| identity_app_links |
Links identities to app-specific user records |
| oauth_authorization_codes |
OAuth2 authorization codes |
Key Columns
| Table |
Column |
Type |
Notes |
| identities |
did |
TEXT UNIQUE |
did:web:last1.id:identities:<id> |
| credential_issuers |
did |
TEXT UNIQUE |
did:web:last1.id:issuers:<id> |
| app_clients |
did |
TEXT UNIQUE |
did:web:last1.id:apps:<app_id> |
| credentials |
signature |
TEXT |
Legacy base64 Ed25519 signature |
| credentials |
credential_vc |
JSONB |
Full W3C VC envelope with proof |
| issuer_keys |
public_key |
TEXT |
PEM-encoded Ed25519 |
| issuer_keys |
private_key_encrypted |
TEXT |
AES-256-GCM encrypted |
5. API Endpoints
DID Resolution (public, no auth)
| Method |
Path |
Returns |
| GET |
/.well-known/did.json |
Root DID document |
| GET |
/issuers/:id/did.json |
Issuer DID document with verification methods |
| GET |
/identities/:id/did.json |
Identity DID document |
Credentials
| Method |
Path |
Auth |
Purpose |
| POST |
/api/credentials/issue |
App (credentials:issue) |
Issue credential; signs with issuer key |
| GET |
/api/credentials/verify/:id |
Public (if profile_public + allowlist) / Owner / App |
Returns credential + VC + signature + public key |
| GET |
/api/credentials/status/:id |
Public |
Returns credential status (active/revoked/expired/suspended) |
| GET |
/api/issuers/:issuerId/public-key |
Public |
Returns issuer public key |
Verification (presentation layer)
| Method |
Path |
Auth |
Purpose |
| POST |
/api/verify/credential |
None |
Stateless VC verification; accepts signed VC + optional public key |
Identity
| Method |
Path |
Auth |
Purpose |
| GET |
/api/identity/public/:idOrUsername |
Public (if profile_public) |
Public profile |
| GET |
/api/identity/me |
User |
Current identity + linked providers |
| GET |
/api/identity/signals |
User |
Trust signals (no score) |
| GET |
/api/identity/credentials |
User |
List credentials |
| GET |
/api/identity/credentials/export |
User |
Export v3: identity, credentials with VCs, issuers keyed by DID |
| POST |
/api/identity/credentials/verify-human |
User + Turnstile |
Issue human_verified |
| POST |
/api/identity/credentials/request-phone-verify |
User |
Send OTP |
| POST |
/api/identity/credentials/verify-phone |
User |
Verify OTP, issue phone_verified |
| PATCH |
/api/identity/profile |
User |
Update profile_public, username |
| GET |
/api/identity/app-links |
User |
Connected apps |
| GET |
/api/identity/consent |
User |
Consent grants |
| GET |
/api/identity/trust-events |
User |
Trust events |
| GET |
/api/identity/reputation/snapshots |
User |
Reputation snapshots |
OAuth
| Method |
Path |
Auth |
Purpose |
| GET |
/api/oauth/authorize/validate |
None |
Validate client_id, redirect_uri, scope |
| POST |
/api/oauth/authorize/approve |
User |
Create auth code |
| POST |
/oauth/token |
App (Basic) |
Exchange code for access token |
Trust Events
| Method |
Path |
Auth |
Purpose |
| POST |
/api/trust-events |
App (Bearer + X-App-Id or Basic) |
Ingest trust events |
6. Trust Model
Principles
| Rule |
Implementation |
| App-agnostic |
trust_events use generic event_type |
| Portable |
Credentials use DIDs; export includes VCs |
| Proof-based |
Signals from credentials and trust_events |
| No centralized score |
Identity Strength shows checkmarks only |
| Trusted issuers only |
Issuance requires valid credential_issuers row |
| Trust events append-only |
Insert only; no update/delete |
Credential Issuance Rules
- App has
credentials:issue or credentials:write scope
- Identity granted consent to the app
- credential_type in issuer's
allowed_credential_types
- Credential references registered issuer
7. Centralized vs Decentralized
| Aspect |
Status |
| Credential verification |
Decentralized — DID doc + proof = offline-verifiable |
| DID resolution |
Decentralized — did:web via HTTPS |
| Credential portability |
Decentralized — VC export |
| Issuer discovery |
Decentralized — DID documents |
| Identity creation |
Centralized — platform-managed |
| Private key storage |
Centralized — encrypted in Supabase |
| Credential issuance trigger |
Centralized — via Last1 ID API |
| Status checks |
Centralized — hit Last1 ID for revocation |
| DID document hosting |
Centralized — last1.id serves them |
8. Environment Variables
| Variable |
Required |
Purpose |
| SUPABASE_URL |
Yes |
Supabase project URL |
| SUPABASE_SERVICE_ROLE_KEY |
Yes |
Server-side Supabase access |
| VITE_SUPABASE_URL |
Yes |
Client Supabase URL |
| VITE_SUPABASE_ANON_KEY |
Yes |
Client Supabase anon key |
| CREDENTIAL_SIGNING_KEY |
Yes |
32+ chars; encrypts issuer private keys |
| TURNSTILE_SECRET_KEY |
Optional |
human_verified credential |
| VITE_TURNSTILE_SITE_KEY |
Optional |
Client Turnstile |
| TWILIO_ACCOUNT_SID |
Optional |
phone_verified credential |
| TWILIO_AUTH_TOKEN |
Optional |
phone_verified credential |
| TWILIO_VERIFY_SERVICE_SID |
Optional |
Must start with VA |
| SITE_URL |
Production |
CSRF origin validation |
| RADIOCHECK_APP_SECRET |
Per-app |
Trust event ingestion |
| MATR_IOS_APP_SECRET |
Per-app |
Trust event ingestion |
| LAST1_APP_SECRET |
Per-app |
Trust event ingestion |
9. File Map
Server Lib
| File |
Purpose |
| did.ts |
DID generation, document building, VC construction |
| credentialSigning.ts |
Key gen, encrypt/decrypt, sign/verify, VC signing |
| credentialStatus.ts |
resolveCredentialStatus() |
| credentials.ts |
System credential issuance (issueCredentialIfMissing) |
| identity.ts |
getOrCreateIdentityForUser, upsertLinkedAuthProvider |
| identitySignalsService.ts |
Trust signals computation |
| auth.ts |
Supabase auth user resolution |
| appClientAuth.ts |
App client auth (Bearer, Basic) |
| oauth.ts |
OAuth token logic |
| reputation.ts |
Reputation snapshot generation |
Server Routes
| File |
Purpose |
| did.ts |
DID document serving |
| verify.ts |
Credential presentation/verification |
| credentials.ts |
Credential issuance, verify, status, public-key |
| identity.ts |
Identity, profile, credentials, export, consent |
| oauth.ts |
OAuth authorize + token |
| trustEvents.ts |
Trust event ingestion |
| appClients.ts |
App client registration |
| admin.ts |
Admin gateway |
10. Migrations (Chronological)
- identities, linked_auth_providers, app_clients, consent_grants
- credential_issuers, credentials, trust_events, reputation_snapshots
- identity_app_links, seed_app_clients
- auth_and_onboarding (auth_user_id, onboarding_completed_at)
- phone_verification
- app_client_registration
- radiocheck_redirect_uris
- identity_platform_additions (last_used_at, system issuer)
- internal_app_redirect_uris
- tune_redirect_uris
- matr_b2b_rename_to_matr_biz
- identity_public_profile (username, profile_public)
- credential_issuer_allowed_types
- oauth_authorization_codes
- credential_issuers_trust_level
- issuer_keys
- credentials_signature
- did_and_vc (did columns, credential_vc)
11. Next Steps (Roadmap)
- User-controlled DIDs — Allow users to bring did:key or did:ion
- OpenID4VCI — Standards-based credential issuance
- OpenID4VP — Presentation request/response flow
- Bitstring Status List — Publish status bitstrings
- External wallet support — CHAPI or OID4VP export
- DID method migration — did:dht or did:tdw for self-sovereign identifiers
12. Internal System Admin Control Plane
Domain and Purpose
- Internal portal domain:
admin.last1.enterprises
- Scope: ecosystem-level operations for
last1.id, last1.app, radiocheck.app, realoutcomes.app
- Not an org/customer admin console
Roles
super_admin
platform_admin
security_admin
support_admin
read_only_auditor
Security and Privacy Posture
- Gateway-authenticated admin routes with signed headers
- Membership + role enforcement from
system_admin_memberships
- Capability-gated mutations (identity/issuer/policy/app client/key/service operations)
- Append-only admin audit logging in
admin_audit_logs
- No private-key exposure in admin APIs or UI
- DID/VC trust model remains proof-based and portable; no reputation score added