One tap on a refill-reminder text or email and the patient lands in
the refill wizard already logged in — no DOB entry, no verification
code. Azure runs the bridge; Salesforce serves the wizard.
When SFMC sends a refill-reminder text or email, the message carries a
short URL. The patient taps it once and lands inside the Salesforce
refill wizard already logged in — no DOB lookup, no verification code,
no password. Three systems each do one thing: SFMC handles the send
(hooks into the existing refill-reminder pipeline — no new flow);
Azure mints the link, holds the signing key, and runs the OAuth
handshake at click time; Salesforce establishes the session and serves
the wizard.
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.
§2How the bridge works
SFMC sends the message; Azure mints the link, holds the signing key,
and runs the OAuth handshake; Salesforce establishes the session and
serves the wizard. Three systems, one job each.
Send
SFMC
Refill reminder
SMS or email
→
Bridge
Azure Function
Mint · Sign JWT · Exchange VNet · Key Vault · SQL
→
Session
Salesforce
singleaccess → Refill wizard
Step by step
SFMC decides it's time to remind
The existing JBSystemFlow_Refill_Reminder_c picks the
patient and selects channel (SMS or email).
SFMC asks Azure for a link
At template render, AMPScript HTTPPost2 hits the
Azure mint endpoint with the patient's Contact Id, channel, and an
idempotency key.
Azure mints + stores
Generates a 12-char base62 short code, stores the HMAC hash in SQL
with a 72-hour TTL, returns the short URL to SFMC.
SFMC sends the message
The text or email goes out with the link
https://login.advancedrx.net/r/Kj3pQ9xMv7nR.
Patient taps the link
Browser hits Azure (one tap, no interstitial — see §5). Azure
looks up the hashed code, resolves Contact → Salesforce username
via the local cache.
Azure signs the Salesforce JWT
ECA private key never leaves Key Vault —
CryptographyClient.SignAsync handles the signature
in-vault.
JWT Bearer → access token → frontdoor
Azure POSTs the assertion to Salesforce's token endpoint, gets an
access token, swaps it at /singleaccess for a
one-time-use redirect URL.
Patient lands logged in
303 redirect to the Salesforce frontdoor URI; Salesforce
establishes the session and serves the refill wizard. Total time:
under a second.
§3Why Azure
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.
Public ingress hardening
— Azure Front Door + WAF + per-IP rate limiting at the edge.
Salesforce can't easily do this.
Key Vault-backed signing
— the ECA private key signs in-place; it never leaves the vault.
Sub-millisecond SQL —
hash lookups at click time without governor limits or Apex CPU caps.
Contact cache already in place
— Azure resolves Contact → Salesforce username locally; no
round-trip to Salesforce at click time.
Reduced attack surface —
no community-reachable Apex endpoint is required for this feature;
the link-mint surface lives on Azure behind WAF + private auth.
Real observability — App
Insights for ops telemetry, scrubbed PHI-clean.
§4Salesforce-side surface
Because the link expires by time rather than by event, the Salesforce
footprint is small and well-bounded. Two items max:
1
External Client App — the trust record
Holds Azure's public signing certificate, the OAuth scopes Azure can
request, the "admin pre-authorized users" policy bound to the
Customer Community Plus Login profile, and IP relaxation (clicks
come from arbitrary patient IPs). In source-format metadata this is
one ECA file plus its policy file; logically one deliverable.
+0 or 1
Permission set for the ADF integration user (if needed)
Azure's nightly ADF job extends to mirror portal User records
alongside the existing Contact cache. If the integration user
already has User-read access, no change. If not, one small permset
grants it. To confirm pre-build.
Explicitly not in scope on the Salesforce side: Apex, Named
Credentials, flows, community-reachable endpoints, Custom Objects, Big
Objects, LWC, public Experience Cloud routes, CMDT allowlists,
AMPScript JWT minting.
§5Key design decisions
Three calls shape the architecture. Each was evaluated explicitly
against alternatives; each is reversible if practice proves the trade
wrong.
5.1 — Time-based expiry vs event-based
The link can either expire on a clock (time-based) or be killed
the moment the patient submits a refill (event-based via a
Salesforce → Azure webhook). Event-based gives tighter kill
precision but requires Apex callout wiring, a Named Credential, an
Azure endpoint, and tests on both sides.
✓ Chosen
Time only — 72-hour TTL
Link expires by clock, not by event. Bounded blast radius
(refills of existing prescriptions to saved address only)
accepted. Keeps the Salesforce-side surface to a single
metadata record.
Deferred
Webhook on completion
Tighter kill precision (seconds, not hours). Engineering cost:
one Apex class + Named Credential + Azure endpoint +
trigger-event wiring + tests on both sides.
5.2 — One-click vs interstitial
Strictest posture: a "Tap to continue" interstitial page that
blocks link scanners from triggering Salesforce sessions inside
their sandboxes. Industry norm (Slack, Substack, Medium): one
click, accept that scanners briefly hold ephemeral sessions.
✓ Chosen
One click — no interstitial
Matches Slack/Substack-grade UX. Scanner-induced sessions live
only inside the scanner's ephemeral HTTP client and
self-destruct. Audit log flags ScannerSuspected
via UA signatures so triage stays clean.
Deferred
Explicit "Tap to continue"
Strictest scanner protection. One extra tap on the patient's
side. Reversible to this design in a single-handler change if
Salesforce-API volume from scanners proves material at
rollout.
5.3 — Front Door tier: Standard vs Premium
Front Door Premium adds managed WAF rule sets, Bot Manager, and
Private Link to origin — $295/mo more than Standard. For one
narrow magic-link route, custom WAF rules + good function-side
validation get most of the value.
✓ Chosen
Standard — ~$35/mo
Custom WAF rules + per-IP rate limiting + TLS + custom domain
+ edge logging. Sufficient for a single narrow public endpoint
with strict input validation behind it.
Deferred
Premium — ~$330/mo
Worth it if/when we put other public Azure surfaces behind the
same edge (storefront, outbound fax intake, future
patient-facing endpoints). Then $295/mo delta amortizes across
the platform.
§6Two pre-build spikes (gates)
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.
✓ Spike A · Salesforce · PASSED
JWT Bearer + singleaccess for CCP Login
Proved the full handshake works for a Customer Community Plus
Login license user. Minted a JWT locally, exchanged at the
community token endpoint (returned access_token + community URL),
POSTed to /singleaccess (returned
frontdoor_uri JSON), followed the redirect chain
(sid session cookie set, HTTP 200 on the storefront
page).
Verified 2026-05-18 in ClaudeTest · three pre-auth gotchas
captured in plan.md Phase 0 + a new Phase 4 SetupEntityAccess
wiring step.
✓ Spike B · SFMC · SOFT-PASSED
Link wrapping + fragment behavior
Production SFMC self-send delivered both fragment (`/r#…`) and
path (`/r/…`) URLs to Gmail with the 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.
Verified 2026-05-21 via production self-send · four execution
gotchas + AdvancedRx SFMC infrastructure facts captured in
plan.md.
§7Cost
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.
Dedicated, always-warm, isolated blast radius from eFax
~$150–250
SQL · reuse existing
Two new tables on existing DB
~$0
Key Vault signing ops
Per-click sign call; volume-priced
~$5
App Insights
Sampled + scrubbed
~$5–25
Total · estimated
Realistic v1 range
~$200–315 / mo
§8What's next
Both gating spikes are cleared. The remaining unblockers are
out-of-band coordination items.
✓ Spike A passed
(CCP Login + JWT Bearer + singleaccess verified 2026-05-18) ·
✓ Spike B soft-passed
(fragments + paths survive SFMC delivery 2026-05-21). Real
journey-send wrapping behavior verifies during Phase 6a A/B rollout.
SFMC credential rotation completion
— tracked in MARISSA-HANDOFF.md §2 #2. This work waits
on that.
Risk acceptance per channel
(SMS / email link-compromise vectors documented in §5 of the plan,
Kyle as compliance counsel of record).
If Spike A fails, an alternative Salesforce-only architecture is
available as a fallback design record at
../magic-link-portal-login.md.
§9Verification basis
The architecture is reviewed against the existing Azure infrastructure
repo and the live Salesforce + SFMC landscape.
Azure side: Codex audit conducted 2026-05-18 against
advancedrx-document-integration — the live eFax Function
App, e-script integration, patient-matcher service, and existing VNet
+ Key Vault + SQL + App Insights pattern. Findings folded into §3, §4,
§7, §8 of the plan.
Salesforce side: aligns with
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.
Spike A: CCP Login + JWT Bearer + singleaccess
verified end-to-end in ClaudeTest 2026-05-18 — full
handshake (token endpoint → singleaccess → frontdoor redirect →
sid cookie set) confirmed for the CCP Login license.
Spike B: Production SFMC self-send 2026-05-21
delivered both fragment + path URLs to Gmail unmodified. Caveat: Test
Sends often skip click-tracking link wrapping; real journey-send
wrapping behavior verifies during Phase 6a A/B rollout. AdvancedRx
SFMC infrastructure facts (sending stack 11, From domain
hello@advancedrx.email, vanity click-tracking host
click.advancedrx.email, dual-DKIM signed, DMARC pass)
captured in plan.md §4.5.