Overview › Identity & Authentication

Section 2 — Identity & Authentication

Card: Identity & Authentication · 12 items · Source: PADI Mobile Scope Alignment v-ceb35f4d Consumer: the unified PADI app — Expo React Native, shipping as an update to the existing PADI main app.

Same question per item as Section 1: can the unified app build this with an endpoint that already exists?

The headline: every item the artefact actually placed in Q1 2027 is buildable today.

Five of the twelve items are in Q1 scope — AUTH-01 to AUTH-05. All five have endpoints. Two of them looked like gaps until the third step of the test was applied properly, and that correction is the substance of this section.


The test

  1. Does the existing mobile app call an endpoint for this? → usable, lowest risk.
  2. If not — does a PADI web front end, or another PADI property, call one? → usable.
  3. Only if neither → a genuine gap PADI must close.

One addition to the vocabulary: Existing — IdP

Section 1 needed two flavours of Existing: mobile-proven and web-captured. This card needs a third, and it changes two verdicts.

The PADI app already calls AWS Cognito's own API directly, bypassing the PADI facade entirely — POST https://cognito-idp.us-west-2.amazonaws.com with X-Amz-Target: AWSCognitoIdentityProviderService.GetUser and the user's accessToken (kms-ios-padi/PADI/data/api/impl/UserAttribute/UserAttributeApi.swift:21-27).

That matters because GetUser is one action among many on that endpoint. Once a client is proven to reach the IdP with a user token, every other user-pool action is reachable the same way — same host, same header shape, same credential. ChangePassword, GlobalSignOut and RevokeToken are standard actions there.

So an item can be absent from the PADI facade and still require no new PADI API. That is Existing — IdP: buildable by the client with no backend work, subject to app-client configuration that PADI controls but does not have to build.

All three tokens are already stored on both platforms — getIdToken(), getAccessToken(), getRefreshToken() (BaseAppSettingsIpm.kt:803-817; iOS sessionRepository.store(tokens.accessToken, …) at SplashViewModel.swift:162,196). The accessToken these actions need is in hand.


What is different about this card

1. Only five of twelve items are in Q1 2027. The artefact's release view splits them:

Bucket Items Meaning
Carried forward from web AUTH-01, 02, 03, 04, 05 Inherited from the Nov 2026 web launch. All five carry the Now chip — confirmed for Q1 2027.
Q1 2027 delta AUTH-06 (no decision chip, DEP), AUTH-08 PRK, AUTH-10 PRK, AUTH-11 DSC Targeted at Q1. AUTH-08 and AUTH-10 parked, AUTH-11 under discussion, AUTH-06 open with a dependency flag.
Sequenced after Q1 AUTH-09, AUTH-12, AUTH-13 Post-Q1 2027.

AUTH-06 is Q1-delta, carries a DEP flag, and is not parked. It is the only item on this card the artefact flags as having an engineering dependency, and it is five features with three different answers. Biometric unlock needs no API and could ship; magic links need PADI to write Lambda triggers. Estimating them as one number will be wrong — see SCOPE-11.

2. Almost nothing on this card carries SPK or DEP. Every one of the 15 items in Section 1 carried both — needs a feasibility check and has an API dependency. On this card exactly one item carries either: AUTH-06 carries DEP, and nothing carries SPK at all. The artefact is not asking for this study; it is treating identity as settled. This section is worth having precisely because that assumption is only two-thirds right — and the one flag that did appear landed on the item that most needed it.

3. Ten of twelve items have no stated requirement. Only AUTH-11 and AUTH-12 have detail drawers — and both are the items not in Q1. Everything committed for Q1 arrives as a title and a flag.

4. AUTH-07 does not exist. The IDs run 01–06, then 08–13. Not an omission on our side.


Read this first — three findings that govern every item

1. The facade is not the whole surface

Endpoint inventories built by reading the PADI facade will under-report what an identity client can do, because the app already reaches past the facade to Cognito. Two Q1 items — AUTH-03 and AUTH-05 — are absent from the facade and available at the IdP. Neither is a gap.

The corollary is a question, not an assumption: those actions depend on app-client configuration (token revocation enabled, the aws.cognito.signin.user.admin scope granted). PADI controls that configuration. Confirming it is PADI-11, and it is cheap to answer.

2. Sign-out has two halves, and only one of them exists

Today sign-out is local only on both platforms — appDelegate.clearData() plus sessionRepository.clear() (MoreViewModel.swift:40-46), and appSettings.clearDataOnLogout() on Android (AuthenticatorInterceptorRefreshToken.kt:61,75,93). No request is made. A stolen refresh token keeps working.

Two separate mechanisms are needed, and it is worth not conflating them:

  • Revocation — actually invalidating the tokens. Cognito GlobalSignOut / RevokeToken. Exists at the IdP.
  • Coordination — telling PADI's other properties the diver signed out. A PADI-global single-logout registry exists at https://slo.global-prod.padi.com/graphql with getSession, createSession and deleteSession operations (padi.aware.flutter/packages/presentation/lib/src/authentication/services/slo_session_client.dart:6-54).

Only AWARE uses the SLO registry. It is the one piece of cross-property identity plumbing that exists in the estate, and the PADI app is not wired to it.

⚠️ The SLO registry is not safe to adopt as built. It authenticates with a static x-api-key hardcoded in the client (slo_session_client.dart:7), not the diver's token, and sessions are addressed by Cognito sub. Anyone holding that key can delete any session for any sub. The production host is also hardcoded, so non-production builds mutate production sessions. The unified app should not embed this key — PADI-14.

3. Token storage is the one thing not to carry forward

Tokens sit in plaintext on all three products — iOS UserDefaults (with KeychainSwift imported but unused), Android plain SharedPreferences, Adventures unencrypted AsyncStorage. Nothing about the endpoints forces this; it is a client choice, and the new app should use expo-secure-store instead. Recorded here because AUTH-02 is where it gets decided, and because biometric unlock (AUTH-06) depends on having somewhere safe to keep a refresh token.


We have built this area too

poc/mobile-poc carries an identity spike on the target stack (ADR 0002, plus a recorded walkthrough at poc/identity_auth_poc.mp4). Its routes are the card's Q1 set: identity/login, identity/signup, identity/forgot-password, identity/address, identity/account-settings, identity/app-settings, identity/webview, identity/api-responses.

So AUTH-01, AUTH-02 and AUTH-04 are not just endpoint-backed — they are built and running in Expo against PADI's hosts. The per-item notes below say where.

Two findings the POC surfaced that endpoint inventories do not:

  • Config stays in two lanes. The Travel host is deliberately not unified with the PADI gateway (ADR 0002 §1). That is the three-realm problem of AUTH-02 showing up in practice, and the POC's answer was separation rather than a single session.
  • Not every PADI surface takes the Cognito bearer. KD7 eLearning uses "the diver's own credentials, not the Cognito Bearer token the rest of the API uses", and the POC stores only the derived base64 token. A unified token broker has to model that exception.

AUTH-01 — Global account creation B2C

Area 01 Identity, Profile & Account · Flags W26 parity API status: Existing — mobile · Feasibility: buildable

Endpoints available. The full registration flow is mobile-proven on the auth facade (api.global-prod.padi.com/auth/api/):

Method Path Source
POST user/exist/legacy Swapi.kt:37-39
POST oauth/register Swapi.kt:69-71
POST oauth/confirm Swapi.kt:75-77

All three are explicitly unauthenticated (@Headers(isAuthorized: false)), as registration requires.

What the payload already carries. SignUpRequest (data/api/request/SignUpRequest.kt) accepts username, password, firstName, middleName, lastName, language (default en-US), birthDate, gender, clientId, guardianEmail and optIn.

Two of those are worth noticing. guardianEmail means the minor-registration path is already modelled at the API — relevant to AUTH-11 and AUTH-12. optIn is a single boolean, and it is the only consent captured at account creation — see AUTH-10.

The legacy triage. user/exist/legacy returns {m2User, cognitoUser, travelUser, status} (CheckUserResponse.kt). It tells the client whether an email already exists in the legacy M2/Macola system, in Cognito, or in Travel — three different onboarding paths from one call. This is the closest thing PADI has to a cross-property identity lookup, and a unified app needs it more than the current apps did.

Gap. None.

Notes for the RN client. clientId is a request field, so the unified app registers under its own Cognito app client — which is the same configuration question as PADI-11. Whether the new app still needs the legacy triage step depends on how far the M2 sunset has progressed (SCOPE-12).

POC coverage. identity/signup and identity/api-responses in mobile-poc — registration exercised on the target stack.

Verdict. Buildable now, and POC-proven. The strongest item on the card alongside AUTH-04.

Questions: PADI-11 (app-client configuration) · SCOPE-12 (is the legacy triage still needed)


AUTH-02 — Session management (token refresh, expiry, re-auth)

Area 01 · Flags W26 parity, Now API status: Existing — mobile · Feasibility: buildable; the architecture is the work

Endpoints available. POST login (Swapi.kt:31-33) and POST token (Swapi.kt:86-88). Refresh is unauthenticated by design and carries the refresh token in the body.

How it works today. Refresh is reactive: a 401 or 403 triggers one refresh attempt, the original request is replayed once, and a second failure forces logout. Android synchronises this in an OkHttp Authenticator (AuthenticatorInterceptorRefreshToken.kt:47-99); iOS queues concurrent failures in requestsToRetry and replays them after a single refresh (RequestAdapter.swift:36-118).

Gap. None in endpoints. The work is architectural, and it is larger than the current apps needed:

  • The idToken expires in 60 minutes and its aud must match the target client, so the exchange re-issues per target — one token does not open everything.
  • Three realms, not one session: PADI gateway (idToken), store (commercetools session bridged from a store-client idToken), Travel (Travel JWT).
  • The current apps never faced this because they never reached the store or Travel; Adventures had its own login and no refresh token at all.

Notes for the RN client. This item is where the token broker gets designed: three credential types, a 60-minute refresh cycle, the store-session bridge, and secure storage. Proactive refresh ahead of expiry is worth preferring over the current reactive-on-401 pattern — on a dive boat with intermittent signal, a forced logout because two refreshes failed is a bad outcome.

POC coverage. identity/login plus the config-lane decision in ADR 0002 — session establishment is proven; the three-realm broker is not, and the POC chose to keep the Travel lane separate rather than unify it. Treat that as the current state of the art, not as the answer.

Verdict. Buildable, and the single largest piece of client architecture in the card. Scope it as session architecture rather than a refresh call.

Questions: SCOPE-7 (does Q1 include the store and Travel realms) · PADI-11


AUTH-03 — Logout / sign out

Area 01 · Flags W26 parity, Now API status: Existing — IdP · Feasibility: buildable; no PADI build required

What it needs. Sign the diver out. For a unified app, out of everything.

Endpoints available.

Purpose Endpoint Class
Revoke all refresh tokens Cognito GlobalSignOut (AccessToken) Existing — IdP
Revoke one refresh token Cognito RevokeToken (Token, ClientId) Existing — IdP
Cross-property logout signal slo.global-prod.padi.com/graphqldeleteSession(sub) Existing — other property

The IdP actions sit on https://cognito-idp.us-west-2.amazonaws.com, which the app already calls with the user's accessToken for GetUser (UserAttributeApi.swift:21-27). Same host, same header shape, same credential — the pattern is proven, only the X-Amz-Target value changes.

Gap. Nothing for PADI to build. Two things for PADI to confirm:

  1. Is token revocation enabled on the app client? Cognito app clients have revocation off in some configurations, and RevokeToken fails without it.
  2. Does the app client grant aws.cognito.signin.user.admin? GlobalSignOut needs it.

Both are PADI-11, and both are settings rather than work.

Notes for the RN client. Revocation and coordination are separate concerns. GlobalSignOut invalidates refresh tokens but does not invalidate an already-issued idToken — that stays valid until its 60 minutes elapse. So sign-out must also clear local state, which is what the apps do today; the addition is the server call, not a replacement for the local one.

On the SLO registry: adopt the mechanism, not the implementation. It is a cooperative flag (logout: Boolean per sub) that other properties poll, not an enforcement point — and its static-API-key auth model is not something to embed in a shipped app (PADI-14).

Verdict. Buildable now, with no backend dependency. Worth doing properly in Q1 rather than shipping local-only sign-out again — a stolen refresh token currently outlives sign-out indefinitely.

Questions: PADI-11 (revocation and scope on the app client) · PADI-14 (user-scoped path for the SLO registry)


AUTH-04 — Password reset / forgot password

Area 01 · Flags W26 parity, Now API status: Existing — mobile · Feasibility: buildable

Endpoints available.

Method Path Source
POST password/reset/initiate Swapi.kt:53-54
POST oauth/reset Swapi.kt:58-59

Two-step: send a code to the email, then submit code plus new password.

Gap. None.

Notes for the RN client. One oddity to carry across deliberately: iOS sends a Referer header pointing at the web forgot-password URL for the reset call, and only for that call (HeaderBuilder.swift:69-71). That looks like a server-side check on where the reset originated. Worth confirming whether the facade requires it, because a native client that omits it may be rejected — a small thing that would present as an inexplicable failure.

Login already handles the adjacent Cognito states: FORCE_CHANGE_PASSWORD and RESET_REQUIRED are both surfaced (UserStatus.swift:22-23), so the reset path has a defined entry point from a blocked login.

POC coverage. identity/forgot-password — the two-step reset exercised in Expo.

Verdict. Buildable now, and POC-proven. Alongside AUTH-01, the least risky item on the card.

Questions: none blocking. Confirm the Referer requirement during implementation.


AUTH-05 — Change password

Area 01 · Flags W26 parity, Now API status: Existing — IdP · Feasibility: buildable; no PADI build required

What it needs. Change the password while signed in — distinct from AUTH-04, which is for divers who cannot sign in.

Confirmed absent from the mobile apps. There is no authenticated change-password anywhere in either codebase. The only password-writing surface is ResetPasswordViewController, which drives the AUTH-04 reset flow. isForceChangePassword is a Cognito challenge state, not a change-password feature.

Endpoints available.

Purpose Endpoint Class
Change password while authenticated Cognito ChangePassword (AccessToken, PreviousPassword, ProposedPassword) Existing — IdP
Alternative on the facade POST /password/change on the auth base Web-captured

Two independent routes. The IdP action needs nothing from PADI but the app-client scope. The facade route appears in the MyPADI endpoint inventory alongside the other auth-base calls — worth confirming it is live, since it would keep all auth traffic on one host.

Gap. None. Same configuration question as AUTH-03 (PADI-11).

Notes for the RN client. Prefer the facade route if it is confirmed live — one host, one error vocabulary, and no direct IdP dependency in the client. Fall back to the IdP action, which is proven reachable. Either way, a successful password change should be followed by GlobalSignOut so other devices are pushed to re-authenticate.

POC coverage. None. identity/account-settings exists but no change-password flow was built, so this one rests on the endpoint evidence rather than on a proof.

Verdict. Buildable now. Recorded as Existing on the strength of the IdP route; the facade route would be better if PADI confirms it.

PADI-12 is answered — yes. POST {COGNITO_URI}/password/change is called by both learning.padi.com/src/store/modules/auth/actions.js:137 and pro.padi.com/src/store/modules/auth/actions.js:165. Prefer the facade route; the IdP action is the fallback. (the API inventory §13.)

Questions: PADI-11 · ~~PADI-12~~ (closed — the facade route is live)


Area 01 · Flags Q1 delta, DEP API status: Gap (partial) · Feasibility: one part buildable today, four parts not

This is five items wearing one ID, and they have three different answers. Estimating it as a unit will be wrong whichever number is chosen. Splitting it is the single most useful recommendation on this card — SCOPE-11.

Confirmed absent. No biometric API is used or even declared in either app — no LocalAuthentication/LAContext on iOS, no androidx.biometric dependency on Android. No hosted UI, no PKCE, no social login.

Feature What it actually needs Status
Biometric unlock expo-local-authentication gating a refresh token in expo-secure-store. No API at all. Buildable today
MFA Cognito AssociateSoftwareToken, VerifySoftwareToken, SetUserMFAPreference exist at the IdP. But POST login on the facade returns a Token, not a challenge — so the MFA challenge/response round trip has nowhere to go. Facade change, or IdP-direct login
Passkeys Cognito supports WebAuthn only through its newer managed-login flows. PADI configuration, almost certainly hosted UI. Gap — PADI
Magic links A custom auth flow with Lambda triggers on the user pool. Nothing like it exists. Gap — PADI
Federated login Hosted UI with an identity-provider configuration. Absent from the app entirely; AWARE uses hosted PADI SSO, so the pattern exists elsewhere in the estate. Gap — PADI

The load-bearing detail. Biometric unlock is what divers actually mean by "log in with Face ID", and it needs zero backend work — it is a local gate in front of a stored credential. It is parked in the same item as magic links, which need PADI to write Lambda triggers. Those should not share a fate.

Notes for the RN client. Biometric unlock only becomes safe once AUTH-02 puts the refresh token in secure storage. Sequence it after, not with, session management.

Verdict. Split the item. Recommend biometric unlock for Q1 — cheap, high-visibility, no dependency. Leave passkeys, magic links and federated login parked pending PADI platform decisions. MFA sits in between and depends on PADI-13.

Questions: SCOPE-11 (split this item) · PADI-13 (does the facade surface Cognito challenges) · PADI-11


AUTH-08 — Delete / recover account

Area 01 · Flags PRK parking, Q1 delta API status: Gap · Feasibility: not buildable; and the current state is a live exposure

What exists today is not an API. The app sends an email to a human. EmailTransactServiceImpl.swift:63-90 posts to v1/email/transact with a body that reads, verbatim: "The below user has requested to delete their account via the Account Deletion process in the PADI Native App. Please deactivate their SSO, remove them from all marketing communication lists, and send a confirmation email to the customer when finished."

Three defects in that one path, all worth raising independently of any scope decision:

  1. A manual step sits in a GDPR erasure path. Deletion depends on someone reading an email.
  2. Admin client credentials are hardcoded in the source — a client id and secret inline at EmailTransactServiceImpl.swift:35-36, exchanged for a token via oauth2/token client-credentials grant.
  3. Both hosts are staging, in production codeapi-stage.global-np.padi.com and messaging-stage.global-np.padi.com. Production deletion requests are being sent through the staging messaging system. This is a functional bug, not only a hygiene one.

Endpoints available. Cognito DeleteUser exists at the IdP and would delete the user-pool record. That is not account deletion: the diver's data also sits in Salesforce, SFMC, the LMS, commercetools and Travel. Deleting Cognito alone leaves orphaned records everywhere and breaks the erasure guarantee rather than fulfilling it.

For contrast, PADI Adventures has a real oneDELETE /account/ (travel-rn/app/screens/DeleteAccountScreen.js:95). Different product, different backend, but it shows the shape.

"Recover" has no mechanism at all — no soft-delete, no grace period, no restore. Nothing in any source addresses it.

Gap. Yes, and it is PADI-owned: an orchestrated erasure across every system holding diver data, with a defined recovery window. This is the same missing capability as MYP-09 and PREF-03 — the third place it has surfaced.

Verdict. Not buildable. Correctly parked. But the existing path should be fixed regardless of whether this item is ever scoped — flagged as INT-5.

Questions: PADI-9 (consent and privacy systems) · PADI-15 (intended erasure mechanism and owner) · INT-5 (the current path is defective)


AUTH-09 — Preferred login method

Area 01 · Flags PQ1 post-Q1 API status: Deferred · Feasibility: out of Q1 scope, and blocked on AUTH-06 regardless

Sequenced after Q1 2027. No detail drawer.

Worth one observation: the storage for this already exists. The Personalization service is a schemaless key/value store (GET/POST p/personalization/api/Personalization/attributes, PersonalizationApi.kt:11-17) currently holding exactly one key, china_data_consent. A login-method preference would need no new endpoint.

What does not exist is the thing to store — a choice between login methods presupposes AUTH-06. Scope them together when they return.


AUTH-10 — Comply with GDPR and local data requirements on account creation

Area 01 · Flags PRK parking, Q1 delta API status: Gap · Feasibility: not buildable as specified

What exists. optIn: Boolean in SignUpRequest — one flag, no category, no timestamp, no versioned policy reference, no record of what the diver was shown.

For regional handling there is exactly one precedent: the china_data_consent key on the Personalization store, gated by a geolocation lookup (geolocation.padi-prod.padi.com, UtilsApi.kt:31-34) for China PIPL. That is a single-jurisdiction special case built once, not a framework.

Gap. A consent-capture system: which policy version was presented, when, in what language, what was agreed to, and an auditable record of it. The source is explicit that none exists — "Privacy (data export/delete, consent) → Privacy systems not documented."

This is the same gap as MYP-09, PREF-03 and AUTH-08. Four items across two cards resolve to one missing platform capability. That is worth stating plainly to whoever estimates them, because four separate estimates will be four guesses at the same unknown.

Notes for the RN client. The geolocation-gating pattern is reusable — a jurisdiction lookup at registration driving which consents are required is the right shape, and it already works. What is missing is somewhere to record the answers.

Verdict. Not buildable as specified. Correctly parked. Scope with MYP-09 / PREF-03 as one consent platform, not four features.

Questions: PADI-9 (system of record for consent) · SCOPE-13 (scope the four consent items as one)


AUTH-11 — Parent-Signed Waivers for Child Profiles

Area 01 · Flags DSC discuss, Q1 delta · Jira E28, epic Family & Dependent Accounts · Impact High · Effort Low API status: Blocked · Feasibility: not buildable; a legal prerequisite gates it

One of only two items on this card with a stated requirement.

What it needs, from the scope text: a flow letting a parent sign one waiver covering all linked children, stored against the parent account and accessible to authorised dive centres on consent, with a printable version for markets that require paper.

Blocked, by the artefact's own words. "The waiver template, legal language, and consent model for minors must be reviewed and approved by PADI Legal before this feature is built — this is a non-negotiable legal prerequisite."

Endpoints available. A document store does exist, and both learning.padi.com and pro.padi.com call it: TrueVault, a compliance-grade vault for signed diver forms — GET {TRUEVAULT_URI}/Search/Diver · /Search/Member · /Search/blob/{id} · /Search/document/{id} and POST /Truevault/Data (multipart), returning blobIds, formData, medicalRequired, createdDate, memberName (learning.padi.com/src/store/modules/forms/actions.js:10-163). See the API inventory §13.

No signature capture and no consent-scoped sharing endpoint appears anywhere. But storage — the part this item was said to lack entirely — exists and is already in production use for signed diver forms, which is the closest analogue to a waiver PADI has.

The family primitives remain thin: guardianEmail in SignUpRequest and the custom:guardian_email Cognito claim — enough to email a guardian, nowhere near enough to link profiles or scope a document to them.

Two dependencies beyond Legal. The scope names E11.2 and E12 (Digital Fitness-to-Dive & Portable Waiver). Child-profile linking lives in the Family — parent / child account creation card, which this study has not reached. AUTH-11 cannot be built before the thing it attaches to.

On the estimate — softened, but still challenge it. High impact / Low effort was called out when this item appeared to have no substrate at all. TrueVault changes that: "Low effort" is defensible for a signing UI over an existing document service, and there is now an existing document service.

What is still missing is signature capture, a consent-scoped sharing model, and the family-linking data model — plus PADI Legal sign-off, which gates everything regardless. So the estimate is no longer obviously wrong; it is unverified against three absent pieces rather than four.

Verdict. Not buildable. Correctly under discussion. The order of operations is Legal → family account model → portable waiver service → this item.

Questions: PADI-16 (storage exists — is TrueVault the intended home for waivers, and what scopes sharing to a dive centre) · INT-6 (challenge the Low effort estimate)


AUTH-12 — Age-18 Transition Flow

Area 01 · Flags PQ1 post-Q1 · Jira E29, epic Family & Dependent Accounts · Impact Medium · Effort Medium API status: Gap · Feasibility: out of Q1 scope; the hard part is PADI-side by its own scope text

What it needs. On a child's 18th birthday, convert the child profile into an independent account with its own login, after an explicit consent step, carrying over all certification and eLearning history, and update the parent's account.

Endpoints available. None for any part of it. Account creation exists (AUTH-01); nothing migrates a record from one identity to another.

The scope text draws the boundary itself: "Any changes to certification records held in the LMS are outside Axelerant's scope." Certification and eLearning history is exactly what has to move. So the migration — the substance of the item — is PADI's to build, and the client's share is the consent screen and the notification.

Open by PADI's own admission. Scope line 5 asks PADI Legal and Engineering to confirm the mechanism: automatic on the birthday, diver-triggered from a notification, or parent-initiated. Those are three different builds.

Verdict. Not buildable, correctly post-Q1. When it returns, the estimate should cover the consent flow and notification only, with the record migration named as a PADI dependency rather than absorbed.

Questions: PADI-17 (identity migration mechanism and owner) · SCOPE-14 (which of the three trigger models)


AUTH-13 — Global account creation B2B

Area 01 · Flags PQ1 post-Q1 API status: Deferred — endpoints available · Feasibility: out of Q1 scope by sequencing, not by capability

Corrected 2026-09-10. Previously recorded as a gap on the basis that nothing creates a professional account. Reading the web front ends' source disproved that.

Sequenced after Q1 2027. No detail drawer.

What exists. The consumer registration flow (AUTH-01), and enough of a pro concept to show that B2B identity is modelled server-side but not creatable from a client:

  • custom:affiliate_id and custom:affiliate_type_id on the Cognito ID token (IDToken.swift:11-50) — affiliate type is already a first-class claim
  • user/exist/legacy reports pro status as part of its triage
  • Pro reads are mobile-proven — eCard/HaseCardPro, eCard/GetAlleCardListPro (ECardsApi.kt:12-13), the Pro API at api.pro-prod.padi.com, ProChek

Corrected — the endpoints exist. POST {PRO_API}/pros/account/create/member and POST {PRO_API}/pros/account/create/store are called by pro.padi.com/src/api/account/index.js:6,17. B2B account creation is served; it simply is not served from a consumer app. That is unsurprising — B2B onboarding involves credential verification and commercial terms that do not belong in a consumer app flow.

Verdict. Deferred, not blocked. The endpoints exist; the open question is whether a consumer app is the right surface for them (SCOPE-15). When this returns it should be estimated as a UI-and-flow item, not as waiting on a PADI build.

Questions: SCOPE-15 (is B2B account creation in the consumer app's scope, or a separate pro surface)


Summary

Status Items Count
Existing — mobile AUTH-01, AUTH-02, AUTH-04 3
Existing — IdP AUTH-03, AUTH-05 2
Gap AUTH-06 (partial), AUTH-08, AUTH-10, AUTH-12 4
Blocked AUTH-11 1
Deferred AUTH-09, AUTH-13* 2

* AUTH-13 is Deferred — endpoints available: out of Q1 by sequencing, not by capability.

The finding that matters most

All five Q1 items are buildable today, and none needs a new PADI API.

AUTH-01, AUTH-02 and AUTH-04 are mobile-proven. AUTH-03 and AUTH-05 are reachable at the IdP the app already calls directly. What they need from PADI is not development — it is confirmation of two app-client settings (PADI-11), which is a configuration answer, not a backlog item.

That is a materially better position than Section 1, where ten of fifteen items had endpoints and three gaps still need PADI to build. Here the Q1 subset is clean.

The five gaps, and what they really are

Only one of them is a distinct engineering problem:

  1. Consent and privacy platform — AUTH-08, AUTH-10, plus MYP-09 and PREF-03 from Section 1. Four items, one missing system. Estimate once (SCOPE-13).
  2. Family account model — AUTH-11, AUTH-12, and the whole Family card. Blocked on PADI Legal before any engineering.
  3. Advanced auth methods — AUTH-06, of which biometric unlock needs no API and should be split out (SCOPE-11).
  4. B2B onboarding — AUTH-13, post-Q1, and arguably not a consumer-app feature.

Three risks that are not about missing endpoints

  • Sign-out does not revoke anything today. Local-only teardown means a stolen refresh token outlives sign-out indefinitely. AUTH-03 fixes it at no backend cost; shipping local-only again would be a deliberate choice.
  • The account-deletion path is defective in production — hardcoded admin credentials, and staging hosts in release code, in a GDPR erasure flow (INT-5). Independent of whether AUTH-08 is ever scoped.
  • The SLO session registry is the only cross-property logout plumbing that exists, and it is not safe to adopt as built — static API key, sessions addressed by sub, production host hardcoded (PADI-14).

What this card does not carry

No SPK and no DEP flags on any of the twelve items. The artefact treats identity as settled and inheritable. For AUTH-01 to AUTH-05 that reading is right. For AUTH-06 it hides five features with three different answers, and for AUTH-08 it hides a live production defect. Those two are what this section adds.