Status · 2026-09-10 · IN PRODUCTION · Salesforce side deployed 2026-09-03 · Azure cutover 2026-09-09 · Production redeem proven both paths 2026-09-09 · Real messages carrying working links 2026-09-10 · Launch Mon 2026-09-14
One tap on a refill-reminder text and the patient lands on their My Home page already logged in — no date of birth to enter, no verification code to fetch. Email works differently since [D16] (2026-08-06): emailed links land on a date-of-birth step-up before the login runs, so the tap alone no longer completes it. Salesforce mints the link at dispatch time; Azure runs the bridge; SFMC renders it as a merge field. As of 2026-09-10 the whole journey is proven in production — the Salesforce side went live on 3 September, Azure was pointed at the real Salesforce on the 9th, a production link signed the test patient in on both paths that afternoon, and on the 10th a real text and a real email carried working links and each one signed them in. The safety switch is still on, so only test patients can receive a link. What remains is launch: the permission grant for every existing portal user on Friday, the go/no-go, and on Monday the journey switch, the safety switch off, and one real patient on one channel.
Everything this plan describes is built and installed in the real systems, with the safety switch on so no real patient can receive a link yet. The go-live journeys stay off until launch morning by decision. The day-by-day record is magic-link-go-live-sequence.md; this page is the architecture.
Magic_Link__c, the settings record, four
flows including the SMS redaction, the credentials, both permsets.
The bridge app was built by hand the same day with the real
certificate — copying it across lands it with OAuth silently off.
/my-home, email through the redesigned
date-of-birth page. Login History labels them
Magic Link Bridge, so adoption is countable. On the 10th a
real text and a real email carried working links and each signed
them in.
Azure platform built, deployed, security-hardened (2026-06-11), and re-verified live (2026-06-22). Auth proven end-to-end in the sandbox. Direction change 2026-07-08: the mint caller moves from SFMC to Salesforce core — the send path is no longer gated on the SFMC credential rotation; the new open work is the Salesforce-side mint caller (design + build).
singleaccess bridge. SF
LoginHistory 4/4 success from NAT IP
135.119.140.149, zero failures (2026-05-26).
One live exposure + eight landmines. Adversarially verified; build + 11 tests green. State tags: live deployed to prod · repo / decided shipped in code or a recorded decision.
allow=false
2026-06-22.
usp_CreateMagicLink idempotency revive
live
(contactId, idempotencyKey) after
expiry/auto-revoke no longer hits a
UNIQUE(ShortCodeHash) 500 — the proc now matches in
any state and revives the row; 2627/2601 → THROW 50409.
HashPepperVersion; mint regenerates the
short URL with the row's stored pepper version on replay. Rotation
no longer breaks live links. Unit tests added.
/healthz WAF rate-limit + pepper cache
live
ScannerSuspected for observability;
do not gate the bridge — correct for 72h
multi-use links (a false positive would block a real patient). No
behavioral change.
MagicLink:Settings:Sentinel;
reverting the endpoint values alone won't propagate. Runbook now
says bump the sentinel (or restart) at cutover.
SyncControl bookkeeping
repo
Sync_SFDC_PortalUser_Full now records
SetSyncInProgress / UpdateSyncSuccess + an idempotent bootstrap
row (activates with Phase 2 portal-user sync).
SfmcTokenValidator OIDC caching
repo
ConfigurationManager is cached per metadata
address (it was rebuilt per request) — the validator is a DI
singleton.
Committed 2026-07-08 (plan.md revision 11; authoritative decision record in the doc-integration enhancement plan §6): the mint request originates from Salesforce core, not the Marketing Cloud journey. Azure is unchanged — it still generates, stores, redeems, and bridges the link; only the prompter changes. Nothing gets unwound: the SFMC mint wiring was never built and its Entra secret was never handed to Marketing Cloud.
HTTPPost2 to mint at render time
shortUrl; SFMC renders a merge field
maxBatchSize 2, so mint runs synchronously there.
That batch size must not be raised.
Magic_Link__c object, not a field on
Refill_Reminder__c. URL stored as Text rather than URL
(a clickable field would authenticate the clicker as the patient,
with no symptom), blanked about an hour after mint; read-only
"Magic Link: View All" permission set gates who can see it.
MagicLink-Salesforce-Client, allowlist its appId
(config-only on Azure), build the External + Named Credential;
retire the never-distributed SFMC client.
When a refill-reminder text or email goes out, the message carries a short URL. The patient taps it once and lands on their My Home page in the Salesforce portal already logged in — no date of birth to enter, no verification code to fetch. What it replaces: the normal portal login is email address + date of birth, then a one-time code sent to that address. There is no password at any point, so nothing here is "skipping a password" — a phrasing that has appeared in several documents and is wrong. On the email channel, [D16] (2026-08-06) adds a date-of-birth step-up before the login runs, so there the tap alone no longer completes it. Three systems each do one thing: Salesforce decides who gets reminded and asks Azure for the link at dispatch time (the 2026-07-08 direction change); Azure generates the link, holds the signing key, and runs the OAuth handshake at click time; SFMC renders the pre-minted URL as a merge field and delivers the message. Salesforce then establishes the session and serves My Home.
The bulk of the build lives in the existing AdvancedRx Azure VNet — the same one that already hosts eFax, the e-script integration, and the patient-matcher service. The Salesforce footprint stays small; §4 lists exactly what's required there.
Salesforce asks for the link and fires the journey event; SFMC renders and delivers the message; Azure mints, holds the signing key, and runs the OAuth handshake at click time; Salesforce establishes the session and serves My Home. The refill wizard is not opened by the link.
singleaccessRefill_Reminder__c scheduled-path flow fires at the
record's Send_Date_Time__c, and
JBSystemFlow_Refill_Reminder_c (a
Salesforce flow, not SFMC) fires the bulk event
that enters the SFMC journey. Under the 2026-07-08 direction it
also mints the link before firing that event — SFMC's
job from here is render + deliver.
@InvocableMethod Apex action behind a Named
Credential (Entra client credentials as
MagicLink-Salesforce-Client) POSTs to the
machine-only mint host
https://mint.advancedrx.dev/api/magic-links with the
patient's Contact Id and portal User Id (read directly
from Contact.Portal_User__c), channel, retPath, and
an idempotency key (the reminder Id).
{ shortUrl, expiresAtUtc } to
Salesforce.
shortUrl rides the journey-event
payload into the data extension and the template renders it as a
merge field — no AMPScript API call. The message goes out with
the patient-facing link
https://login.advancedrx.net/r/K7QXM3PVN9RW2HTDL4GA
(illustrative — twenty characters, A–Z without I and O, digits 2–9; a
separate host from the machine-only mint endpoint). Blank URL
(mint failed) → the plain reminder still sends — fail-open.
CryptographyClient.SignAsync handles the signature
in-vault.
/singleaccess for a
one-time-use redirect URL.
AdvancedRx already operates a HIPAA-compliant Azure VNet for eFax, e-script, and patient-matcher. Reusing it for magic-link gives wins that are hard to get inside Salesforce.
The bridge-side footprint is small and proven: the ECA, cert binding, and demo patient were all verified in the sandbox 2026-05-26; production go-live repeats it against the prod org (§8). The 2026-07-08 direction change added one new delivery — the mint caller, built 2026-08-19 and eligibility-gated 2026-08-24:
AdminApprovedPreAuthorized permitted-users policy bound
via SetupEntityAccess to a small permset, and IP
relaxation (Bypass; clicks come from arbitrary patient
IPs). Five metadata files: ECA, OAuth Settings, Global OAuth
Settings, Configurable Policies, Certificate.
Cert binding: the Key Vault keypair must exist first (Phase
1); then the public cert is bound to the ECA
inline as base64 in
GlobalOauthSettings.<certificate>, deployed via
the metadata API
— no JKS, no Setup-UI import. Salesforce holds the public cert only;
Azure signs with the non-exportable Key Vault key. (Bound + verified
in ClaudeTest 2026-05-26.) Full procedure in
cert-rotation-runbook.md.
Once created, the ECA's consumer key is handed back to Azure as App
Config MagicLink:Salesforce:EcaClientId — Azure redeem
is non-functional until that's set.
MagicLink-Salesforce-Client) + Named Credential
Magic_Link_Mint +
MagicLinkMintInvocable (13/13 tests). The contract
requires an eligibility verdict (2026-08-24):
calls without one are refused and logged
(RefusedNoVerdict); an ineligible patient is skipped
quietly (SkippedIneligible). Since revision 23,
Magic_Link__c is the mint-attempt
record — every outcome upserts a row carrying
Mint_Status__c, with the URL written on
Minted only, so a new channel needs no new fields and
one query covers every lane. The URL stays FLS-gated to
Magic_Link_View_All and auto-blanked ~1 h per [D4].
Fails open per [D2-am] to
B2B_Custom_Exception__c; batch of 2 is the [D2]
tripwire. Remaining: the reminder-flow wiring itself — no longer
[D22]-gated, since D22 was deferred to v2 on 2026-08-25 [D22-am].
Explicitly not in scope on the Salesforce side: community-reachable endpoints, Custom Objects, Big Objects, LWC, public Experience Cloud routes, CMDT allowlists, AMPScript of any kind (the 2026-07-08 direction change removed the last SFMC API call). Apex + a Named Credential are now in scope — the one addition the direction change brought onto the Salesforce side.
Three calls shape the architecture. Each was evaluated explicitly against alternatives; each is reversible if practice proves the trade wrong.
The architecture depends on two things working that aren't documented for our exact configuration. Both spikes are small, parallelizable, and gating — neither requires a single line of production code.
/singleaccess (returned
frontdoor_uri JSON), followed the redirect chain
(sid session cookie set, HTTP 200 on the storefront
page).
SetupEntityAccess.SetupEntityType is
platform-inferred not writable. All folded into plan.md §6 Phase 0
so the production build doesn't re-derive them.
href values
completely unmodified — no wrapping through
click.advancedrx.email. Caveat: SFMC Test Sends often
skip click-tracking link wrapping; real journey/triggered-send
wrapping behavior deferred to Phase 6a A/B rollout for definitive
verification. V2 design accommodates either outcome.
Order-of-magnitude monthly estimate at expected refill-reminder volume. SQL adds are near-zero (reuses existing DB); Key Vault and App Insights are small even at scale.
Updated 2026-09-10. Everything below the next paragraph was written before production and is retained as the record of what the go-live steps were. All of it is now done except the permission grant to the existing cohort, which is Friday 11 September. What actually remains: the grant, QA-C cases C3–C5, go/no-go on the 11th, then on Monday the 14th the journey switch with the safety switch still on, the safety switch off, and one real patient on one channel. Kyle's alerts (five of six untested) and 2am-plan sign-off close by Friday or are formally accepted open. The live day-by-day is magic-link-go-live-sequence.md.
As written before production: the auth flow is proven end-to-end in the sandbox and the Azure plane was security-hardened on 2026-06-11. What remains is the Salesforce-prod go-live plus the one open storefront-render gap (prod-only data, not a flow defect).
Bridge_Success ×2 and SF LoginHistory 4/4
successful logins all from the Azure NAT IP, zero impersonation. The
JWT bridge is exonerated.
Magic_Link_Bridge ECA + permset +
SetupEntityAccess, bind its public cert inline, and hand the
consumer key to Azure. ⚠ SetupEntityAccess is NOT carried by source control
— proven by test 2026-08-25:
a clean five-component deploy into an empty sandbox produced
0 rows against ClaudeTest's 1. The post-deploy Apex
insert (§7.6 step 3) is mandatory, the deploy stays
green without it, and the only symptom is a patient seeing “the login
link has expired” — so run the
SetupEntityAccess verification query before any patient
traffic. Consumer key goes to Azure as
MagicLink:Salesforce:EcaClientId; Azure then reverts
its 3 sandbox App Config values (TokenEndpoint,
SingleAccessEndpoint, EcaClientId) back to prod
and bumps MagicLink:Settings:Sentinel
so running instances pick them up (audit finding #6). Watch-out: the
ECA source has the sandbox org Id baked into
orgScopedExternalApp — swap it for the prod org
Id before deploy. Doesn't touch SFMC creds, so it's not gated. See §4
+ plan §6 Phase 4.
MagicLink-Salesforce-Client (+ allowlist its appId in
Azure App Config — config-only on the Azure side), External + Named
Credential, an @InvocableMethod mint action called
from the reminder pipeline, and a home for the minted URL. Design
open: batch fan-out vs the 100-callout cap, TTL vs dispatch→send
lag, URL field FLS, fail-open. Salesforce reads the portal User Id
directly from Contact.Portal_User__c at mint time — no
data-extension hop (the 2026-05-26 audit facts carry over).
No longer blocked on the SFMC credential rotation
— that stays open for SFMC's own hygiene
(MARISSA-HANDOFF.md §2 #2) but gates nothing
magic-link.
MagicLinkUrl; SMS + OMM email templates
render it as a merge field (blank → plain-reminder fallback).
Send-classification check, one real-send URL-wrapping verification,
then the 10% → 50% → 100% A/B rollout.
If the prod CCP Login + singleaccess exchange fails, an alternative Salesforce-only architecture is available as a fallback design record at ../magic-link-portal-login.md.
The architecture is reviewed against the existing Azure infrastructure repo and the live Salesforce + SFMC landscape.
fn-magiclink-prod-east2 Running + HTTPS-only; SCM and FTP
basic-publishing-credentials both allow=false (finding #1
confirmed live). App Config endpoint values are readable only from
inside the VNet (jumpbox) — confirm / revert at go-live.singleaccess bridge was exercised in
ClaudeTest against the demo portal user. Proof on both
sides: Azure SQL Bridge_Success ×2 /
RedeemCount=2 with zero failures, and Salesforce
LoginHistory showing
4/4 successful logins, all from the Azure NAT IP
135.119.140.149
(2 Magic_Link_Bridge ECA token exchanges + 2 storefront
session handoffs), with zero human/impersonation logins — the JWT
bridge is fully exonerated. The only post-auth failure is the
storefront render (prod-only commerce data; §8 + plan §10 Risk
#19).advancedrx-document-integration. The mint contract in
§7.1 is reconciled directly against the source
(MintMagicLinkFunction.cs) — confirming mint requires
both Contact Id and portal User Id, returns
{ shortUrl, expiresAtUtc }, and authenticates via Entra
OAuth client credentials. Split hosts: machine-only
mint.advancedrx.dev + patient
login.advancedrx.net, both fronted by Azure Front Door.
As-built facts in plan.md §4.6.storefront-data-audit.md (B2B storefront serving at
https://advancedrx.net/vforcesite/ on the CCP Login
license profile), integrations/sfmc.md (the existing
refill-reminder send pipeline at
JBSystemFlow_Refill_Reminder_c), and the in-progress SFMC
credential rotation per MARISSA-HANDOFF.md §2 #2.ClaudeTest 2026-05-18 — full
handshake (token endpoint → singleaccess → frontdoor redirect →
sid cookie set) confirmed for the CCP Login license.hello@advancedrx.email, vanity click-tracking host
click.advancedrx.email, dual-DKIM signed, DMARC pass)
captured in plan.md §4.5.ClaudeTest sandbox on
2026-05-21 to validate the deployable shape before the production
build. Three execution gotchas surfaced — cert binding requires an
imported public cert (not a Salesforce-generated one); ECA policy
enums differ from legacy ConnectedApp (AdminApprovedPreAuthorized
+ Bypass);
SetupEntityAccess.SetupEntityType is platform-inferred,
not writable via Apex. All three folded into plan.md §6 Phase 0 + §7.6
+ the Phase 4 build steps so the production deploy doesn't re-derive
them. The sandbox artifacts are throwaway; production deploy is still
pending. Cert-import procedure:
cert-rotation-runbook.md.MintMagicLinkFunction.cs (requires
contactId + userId + channel +
retPath + idempotencyKey; returns
{ shortUrl, expiresAtUtc }); the Azure-side change is
allowlist-config-only. The SFMC mint wiring was never built and the
MagicLink-SFMC-Client secret was never distributed, so
nothing gets unwound.