AWS Builder Center

Identity-Aware Embedded Chat with Amazon Quick: Per-Student Data Isolation over Relational Data

A guide to embedding an Quick chat agent into an web portal — where the logged-in user's identity automatically governs every row the agent can return from structured dataset connected to RDMS systems. This is a lessons-learned and best-practices write-up grounded in a real production build: the patterns that worked.

A practical guide to Identity-Aware Embedded Chat with Amazon Quick: Per user Data Isolation over Relational Data
Co-Authors: Stephen Elsaker 

Background

A university maintains all student and alumni-mentor records in a relational database (RDBMS) — structured tables containing profiles, majors, career interests, advising notes, and contact details. They want to embed Amazon Quick Suite's chat agent directly into their student portal so tens of thousands of daily users can ask natural-language questions ("find me mentors in finance who were first-gen students") and receive AI-powered mentor matches.
The constraint is strict: student data is sensitive and lives alongside mentor data in the same relational schema. The embedded agent must:
  • Query structured RDBMS tables at runtime — not pre-indexed flat files
  • Accept the logged-in student's identity from the portal session
  • Match students to alumni mentors using their own profile attributes (major, interests, career goals, preferences)
  • Enforce row-level security so each student sees only their own record plus eligible mentor records — never another student's name, GPA, contact details, or advising notes
  • Operate serverlessly inside the existing portal — no separate login, no data replication outside the RDBMS
Core challenge: Propagate the authenticated student identity into the embedded Quick agent, enforce student-level data isolation against structured relational data, and return real-time query results from an operational database — all governed by the university's existing identity and access systems.

Architecture: Three Planes

Think of the system as three cooperating planes — an identity plane that keeps user/group
records in sync, a request plane that mints a per-user embed URL, and a data plane that
answers questions while filtering rows by identity.
Key insight: the portal user is already a real, registered Quick user (provisioned via
SCIM), so the Lambda embeds that identity directly with GenerateEmbedUrlForRegisteredUser.
Every authorization decision — which agents are visible, which datasets are reachable, which
rows are returned — is evaluated by Quick against the real user and their real group membership.
The embedding layer passes nothing that influences row filtering; authorization lives entirely
in the RLS rules datasets and IdP-managed group membership.

Identity Propagation: IdP → SCIM → IDC → Quick

The foundation is that users are not managed in the enterprise IdP and synchronized automatically (IdP → SCIM → IAM Identity Center → Amazon Quick, where users surface with IdentityType = IAM_IDENTITY_CENTER).
  • The IdP is the single source of truth. SCIM auto-provisions/deprovisions users and
    groups into IDC; joiners/movers/leavers are handled upstream with no manual lifecycle in Quick.
  • Group membership drives everything. Groups (e.g. *-Admins, *-Authors, *-Readers) map
    to subscription roles and to agent-level permissions.
  • When the portal needs an embed URL, it passes the already-authenticated user's identity to the
    Lambda as query params (roleName, sessionName), and the Lambda reconstructs the real
    Quick user ARN
    : arn:aws:quicksight:us-east-1:<ACCOUNT_ID>:user/default/<roleName>/<sessionName>.
Because the URL is issued for the registered user, identity-aware access is enforced by the
platform — no translation layer to build or keep in sync. The same real UserName that Quick
resolves from IDC is exactly what row-level security keys off, which is the heart of the pattern.

Solving the Student-Privacy Problem with User-Based RLS

The Two Guarantees

The agent must satisfy two requirements simultaneously, both enforced by Amazon Quick RLS keyed
to the real authenticated user — not by prompt rules or anything injected at embed time:
  1. Student isolation — a student may read their own record and nothing about any other student.
  2. Mentor discovery — every enrolled student may browse the shared alumni mentor pool.
The UserName that RLS matches on is the real registered Quick user (the same identity used to
mint the embed URL, resolved from IDC). At query time Quick resolves the caller's UserName and
group membership and evaluates the RLS rules against them.

Pattern: The Permissions / Rules Dataset

Student isolation comes from a tiny rules dataset with exactly two columns — the
authenticated user and the primary key of the students table. Each row grants one user access to
exactly one student_id — their own.
STUDENT_RLS_RULES
UserNamestudent_id
maria.garcia@university.eduSTU-100245
david.chen@university.eduSTU-100312
aisha.khan@university.eduSTU-100489
... (one row per enrolled student)...
  • UserName holds the exact registered Quick user name Quick resolves from IDC.
  • student_id is the primary key of the students table — the same column that identifies a
    row in the students dataset.
  • Each student maps to a single primary-key value, so the rule grants exactly one row. (The
    format supports comma-separated values for multi-row cases, but here it's strictly 1:1.)
Build this rules dataset from a small table or flat view that joins the enrollment/identity table
to the students primary key, so it stays in sync as students are added or removed.

Pattern: Attaching RLS to the Students Dataset (RowLevelPermissionDataSet)

The students dataset uses student_id as its primary key. RLS is enforced by registering the
rules dataset against the students dataset
via the RowLevelPermissionDataSet property on
CreateDataSet / UpdateDataSet. Matching is by column name: the rules dataset's UserName
column is matched to the caller's identity, and its student_id column is matched to the
same-named column in the students dataset.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// UpdateDataSet (or CreateDataSet) on the STUDENTS dataset
{
"AwsAccountId": "<ACCOUNT_ID>",
"DataSetId": "students-dataset",
"Name": "Students",
"ImportMode": "SPICE",
"PhysicalTableMap": { /* students table; primary key = student_id */ },
"LogicalTableMap": { /* ... */ },

// ---- This block enforces per-student isolation ----
"RowLevelPermissionDataSet": {
"Arn": "arn:aws:quicksight:us-east-1:<ACCOUNT_ID>:dataset/student-rls-rules",
"PermissionPolicy": "GRANT_ACCESS",
"FormatVersion": "VERSION_1",
"Namespace": "default"
}
}
  • Arn points at the STUDENT_RLS_RULES rules dataset.
  • PermissionPolicy = GRANT_ACCESS means "show only rows explicitly permitted" (deny-by-default;
    a user with no matching UserName row sees zero student rows).
  • FormatVersion = VERSION_1 enables the UserName / GroupName column convention.
Net effect: when Maria is logged in, Quick filters the students dataset to
student_id = STU-100245 before the agent sees a row. If she asks for David Chen's GPA or "other
students in my major," those rows are filtered out by RLS — the agent has nothing to return. The
boundary holds regardless of phrasing.

Pattern: Group-Based Discoverability for the Mentor Pool

The mentor pool must be broadly readable while student-to-student data stays isolated, so it uses
a group-based rule scoped to a group every enrolled student belongs to:
MENTOR_RLS_RULES
GroupName(grants the whole pool to the group)
Enrolled-Students*
Because Enrolled-Students membership flows from the IdP via SCIM → IDC, every enrolled student
gains mentor discoverability with no per-student maintenance. The student's stated preferences
(major, interests, career goals) then drive which permitted mentor rows the agent surfaces and
ranks — preferences shape the match; RLS enforces the privacy boundary underneath.
The two datasets carry deliberately different RLS scoping:
DatasetRLS rules datasetMatch columnResult
Students (PK student_id)STUDENT_RLS_RULES (UserName, student_id)UserName → own student_idSees only their own record
Mentor pool (MENTOR_PROFILE_FLAT)MENTOR_RLS_RULES (GroupName)GroupName = Enrolled-StudentsAny enrolled student can discover mentors

The Lambda: Embedding for the Registered User

The embed-URL Lambda does three things: build the real user ARN, ensure the user can use a chat
agent, and mint the URL.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import os, json, boto3

quicksight = boto3.client('quicksight')
ACCOUNT_ID = os.environ['AWS_ACCOUNT_ID']
ALLOWED_DOMAINS = os.environ.get('ALLOWED_DOMAINS', '').split(',')
AGENT_ID = os.environ['AGENT_ID']
AGENT_ARN = f'arn:aws:quicksight:us-east-1:{ACCOUNT_ID}:agent/{AGENT_ID}'

def get_user_arn(event):
"""Build the REAL registered-user ARN from portal-supplied identity."""
p = event.get('queryStringParameters') or {}
role_name, session_name = p.get('roleName'), p.get('sessionName')
if role_name and session_name:
return f'arn:aws:quicksight:us-east-1:{ACCOUNT_ID}:user/default/{role_name}/{session_name}'
return os.environ.get('QUICKSIGHT_USER_ARN', '')

def ensure_reader_pro(user_arn):
"""READER cannot access Chat Agents — auto-upgrade to READER_PRO."""
user_name = user_arn.split(':user/default/')[-1]
user = quicksight.describe_user(AwsAccountId=ACCOUNT_ID, Namespace='default',
UserName=user_name)['User']
if user['Role'] == 'READER':
quicksight.update_user(AwsAccountId=ACCOUNT_ID, Namespace='default',
UserName=user_name, Email=user['Email'], Role='READER_PRO')
return 'READER_PRO (upgraded)'
return user['Role']

def lambda_handler(event, context):
headers = {'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET,OPTIONS',
'Content-Type': 'application/json'}
if event.get('httpMethod') == 'OPTIONS':
return {'statusCode': 200, 'headers': headers, 'body': ''}
try:
user_arn = get_user_arn(event)
role = ensure_reader_pro(user_arn) # auto READER -> READER_PRO
response = quicksight.generate_embed_url_for_registered_user(
AwsAccountId=ACCOUNT_ID,
UserArn=user_arn, # embed FOR the registered user
ExperienceConfiguration={'QuickChat': {}},
AllowedDomains=ALLOWED_DOMAINS)
return {'statusCode': 200, 'headers': headers,
'body': json.dumps({'embedUrl': response['EmbedUrl'],
'agentArn': AGENT_ARN, 'userRole': role})}
except Exception as e:
return {'statusCode': 500, 'headers': headers, 'body': json.dumps({'error': str(e)})}
Worth calling out:
  • IAM permissions: quicksight:GenerateEmbedUrlForRegisteredUser, quicksight:DescribeUser,
    quicksight:UpdateUser.
  • The auto role upgrade is not optional. A plain READER cannot access Chat Agents, so the
    Lambda promotes to READER_PRO (Professional) — factor it into cost planning.
  • The sample uses Access-Control-Allow-Origin: *. Fine for a demo; in production scope it to
    your CloudFront domain and consider a Lambda authorizer in front of the API.

Access Control: Four Layers, All Keyed to Real Identity

Authorization is enforced at four layers, each keyed to the user's real, IdP-governed identity:
LayerMechanismPrincipalExample
Subscription roleGroup → Quick role mappingIDC group (SCIM-synced)*-Admins → ADMIN_PRO, etc.
Agent accessUpdateAgentPermissions granting DescribeAgentgroup/default/<GroupName>Only granted groups can use the agent
Row-level securityRowLevelPermissionDataSet rules datasetsUserName (students) / GroupName (mentors)Own record + shared mentor pool
Defense in depthLake Formation column-level controlsQuick service roleSensitive columns excluded before RLS runs
The four layers compose: a student's group sets their role and agent access, the UserName rule
restricts them to their own student row, the GroupName rule opens the mentor pool, and Lake
Formation keeps the most sensitive columns out of reach entirely — none of it influenced by
anything the embedding layer passes in.

Leveraging Structured Data via RDS Connectors

The student and alumni data lives in a relational database (RDBMS) behind the portal. Amazon
Quick connects via the RDS connector pattern (see the
AWS QuickSight tutorial ):
  1. RDBMS exposed via Amazon RDS (or reachable over VPC) — works for any RDS-supported engine (PostgreSQL, MySQL, SQL Server, Oracle, etc.)
  2. RDS connector configured with a VPC connection, over SSL
  3. Two datasets: a students dataset (private, locked by the UserName → student_id
    rules dataset) and a mentor pool dataset (broadly discoverable via the Enrolled-Students
    group rule)
Mentor pool fields: person_id, full_name, interest_area (matching), major, program,
employer, role_title, class_year, profile_url, and GroupName (RLS match column). The
students dataset is keyed on student_id and locked by STUDENT_RLS_RULES.
SPICE vs. Direct Query: we use SPICE for the mentor pool with a scheduled daily refresh
— alumni profiles change infrequently and SPICE gives the sub-second scan speed chat needs.
Reserve Direct Query for genuinely real-time fields (enrollment status, live availability).

Query Optimization: Topics vs. Dataset Q&A

During testing we found a significant latency gap:
ApproachResponse TimeBehavior
Topics (pre-indexed)~30 secondsPre-indexes fields; single SQL execution
Dataset Q&A~40+ seconds per SQLGenerates multiple queries and combines results
Dataset Q&A sometimes issues several SQL queries per question; Topics pre-index fields so the
system generates one optimized query. What we did:
  1. Topics for the primary agent experience — faster mentor matching.
  2. Smart mode as fallback — routes between Topics and Dataset Q&A by query type.
  3. Simplified schema — fewer columns = faster SPICE scanning and better query generation.
  4. Pre-joined MENTOR_PROFILE_FLAT view — avoids query-time joins.
  5. Rich semantic metadata — field descriptions and synonyms improve query-generation accuracy.
Topics with controlled field access also avoid Dataset Q&A occasionally surfacing columns you
didn't want exposed; Lake Formation back-stops that at the data layer, and RLS still ensures the
students dataset only ever exposes the logged-in student's own row.

Embedded SDK Configuration

The frontend (CloudFront + S3) uses a shell/iframe persistence pattern: a shell.html
(deployed as index.html) never reloads, the chat lives in a persistent container, and only an
inner <iframe id="app"> swaps as the user navigates — keeping the conversation alive on a
single per-session embed URL. The agent is embedded with the Quick Embedding SDK (v2.11.3) and
pinned via fixedAgentArn:
1
2
3
4
5
const embeddingContext = await QuickSightEmbedding.createEmbeddingContext();
const frameOptions = { url: embedUrl, container: '#mentor-match-container',
height: '700px', width: '100%' };
const contentOptions = { fixedAgentArn: agentArn }; // pin to the Mentor Match agent
const embedded = await embeddingContext.embedQuickChat(frameOptions, contentOptions);

Reasoning Mode and Web Search via URL Query Params

Some behaviors are controlled by query parameters on the embed iframe URL, not SDK options —
the cleanest way to standardize the experience (e.g. lock everyone to Smart and hide the picker):
1
{HOST}/sn/account/{ACCOUNT_NAME}/embed/share/accounts/{ACCOUNT_NUMBER}/chatagents/SYSTEM?showReasoningModeSelection=true&defaultReasoningMode=SMART
ParameterValuesEffect
defaultReasoningModeSMART, ADVANCED, FASTSets the initial reasoning mode
showReasoningModeSelectiontrue / falseShow or hide the mode dropdown
  • Lock users on Smart: defaultReasoningMode=SMART and showReasoningModeSelection=false.
  • Web search / attribution: ?showWebSearch=true&showBrandAttribution=true&showUsagePolicy=true

Networking and Security: Private by Design

The API that mints embed URLs is not exposed to the public internet:
  • PRIVATE API Gateway reachable only through a VPC interface endpoint, with a resource
    policy restricting access to that endpoint (aws:sourceVpce). Browsers reach it over VPN /
    Direct Connect — never the open internet.
  • No public endpoint to defend — no WAF needed; the network boundary is the first control.
  • CloudFront + S3 serve the static frontend over HTTPS.
  • The embed URL is single-use and per-session (5-minute redemption, up to 10-hour session).
Production hardening beyond the sample: scope CORS to the CloudFront domain, and add a Lambda authorizer to validate the caller before an embed URL is generated.

End-to-End Flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Student logs into the portal (already a registered Amazon Quick user via IdP→SCIM→IDC)
→ Portal calls the PRIVATE API (via VPC endpoint) with roleName + sessionName
→ Lambda builds the REAL student user ARN
→ Lambda runs DescribeUser; if READER, UpdateUser → READER_PRO
→ Lambda calls generate_embed_url_for_registered_user (UserArn = real student, QuickChat)
→ Returns a single-use embed URL
→ CloudFront/S3 shell renders the SDK (embedQuickChat, fixedAgentArn) in a persistent iframe
→ Student asks: "Find me mentors in finance who were first-gen students"
→ Agent queries the students + mentor datasets (SPICE) via a Topic
→ USER-BASED RLS filters rows by the student's REAL identity:
• STUDENTS: STUDENT_RLS_RULES matches UserName → their OWN student_id ✔
• MENTORS: MENTOR_RLS_RULES matches GroupName = Enrolled-Students ✔
• every OTHER student'
s record → filtered out by RLS ✘
→ Agent returns: "Here are your top 5 mentors in finance, matched to your preferences..."

Lessons Learned

The decisions and tradeoffs that actually shaped the build — grouped by area, each tied to a
concrete consequence. Nothing generic: if a lesson didn't change a decision or save debugging
time, it isn't here.

Identity & governance

  1. Embed the real registered user — never a stand-in. RLS, agent permissions, and audit
    trails all resolve to a real principal automatically. Embed a generic identity and RLS has no
    real UserName to filter on — every user collapses into one access scope and the privacy
    boundary is gone before you write any policy.
  2. Carry identity in the ARN; keep the embed request minimal. Identity is fully expressed by
    the user ARN; the request carries only ExperienceConfiguration={'QuickChat': {}} and
    AllowedDomains. Side-channel identity attributes create a second, drift-prone source of truth
    that RLS doesn't read — so isolation silently depends on the wrong field.
  3. Make the enterprise IdP the single source of identity truth. Users/groups flow IdP → SCIM
    → IDC → Quick. Creating users directly in the analytics layer forks identity from IdP reality
    and produces orphaned accounts that bypass governance.
  4. Map groups to roles; never grant roles per user. Capability follows group membership and
    changes with it. Per-user grants defeat SCIM lifecycle management and leave stale elevated
    access when someone changes teams.
  5. Set agent access with UpdateAgentPermissions — and verify with DescribeAgent. Assuming
    a group mapping implies agent access (without reading it back) is how "I can log in but the chat
    agent says no access" tickets are born. Verification is part of provisioning.
  6. Auto-upgrade READER → READER_PRO. Chat Agents require READER_PRO. Auto-upgrading your entire reader population the moment they touch the app can produce a surprise bill — gate the upgrade on actual chat entitlement, not login, and reconcile counts against entitlement.

Embedding & the embed URL

  1. Treat the embed URL as single-use and short-lived. ~5-minute redemption, ~10-hour session.
    Caching, logging, or sharing it breaks redemption — mint a fresh URL per frame load and lean on
    the long session for the working window.
  2. Register the embedding domain in BOTH allowlists, over HTTPS. Set only one of the Lambda
    AllowedDomains and the account-level allowlist and you get an embed that authenticates but
    renders a confusing blank frame. Verify the frame renders, not just that a URL is issued.
  3. Pin the agent with fixedAgentArn; set per-feature controls where they live. Bind a single
    non-switchable agent via embedQuickChat. File upload, web search, and code interpreter are
    agent-level configuration, not SDK flags — hunting for SDK options that don't exist is wasted time.
  4. Lock reasoning mode at the embed URL. SMART is the default for fresh users, so "stuck on
    Advanced" is a saved prior-session preference, not a platform default. Set
    defaultReasoningMode=SMART + showReasoningModeSelection=false (and the web-search params) to
    standardize. This was our single biggest operational time-saver.

Row-level security (the centerpiece)

  1. Enforce isolation with a user-based RLS rules dataset keyed on the primary key. UserName
    • the students primary key student_id, attached via RowLevelPermissionDataSet
      (GRANT_ACCESS, VERSION_1), so each UserName resolves to exactly one row. Key the rule on a
      non-unique column and one user matches multiple rows — isolation silently fails. This is the
      highest-severity failure mode in the design, and why the primary key is non-negotiable.
  2. Use a GroupName rule for the shared mentor pool — keep it separate from the per-row student
    rule.
    Conflating "shared/discoverable" with "private/per-user" under one rule type either
    over-restricts mentors or under-restricts student rows. Model two intents explicitly — one RLS
    mechanism, two deliberately different scopes.
  3. Validate RLS by impersonating real users, not by reading the rule. A rules dataset that
    looks correct but has a stale/mismatched UserName mapping passes inspection and still leaks.
    Test as at least two distinct students (and one group-only user) and confirm each sees exactly
    their own row plus the expected mentor pool.

Data & performance

  1. Pre-join in the database, never at query time. Query-time joins fan each question into
    multiple joined SQL statements, pushing Dataset Q&A past ~40s and making chat feel broken even
    when correct. Materialize one flat view (MENTOR_PROFILE_FLAT) so Quick scans a denormalized table.
  2. Use SPICE with a scheduled refresh for slow-changing data, and keep the schema lean. Direct
    Query would pay the round-trip and join cost on every question. Load the mentor pool into SPICE
    (daily refresh); reserve Direct Query for real-time fields. Prune columns: both SPICE scan time
    and query-generation accuracy degrade as column count grows.
  3. Prefer Topics over Dataset Q&A, and invest in semantic metadata. Topics pre-index fields and
    emit one optimized SQL (~30s); Dataset Q&A generates multiple queries (~40s+). The gap is
    structural. Make a Topic the primary experience with smart-mode fallback, and author field
    descriptions/synonyms so phrasing maps to the right columns on the first query.

Networking & frontend

  1. Keep the embed-minting plane private by design. Expose the embed API only through a PRIVATE API Gateway via a VPC interface endpoint (aws:sourceVpce); browsers reach it over VPN / Direct Connect. With no public endpoint, there's no public attack surface to defend with WAF/rate limits.
  2. Serve a persistent shell/iframe frontend from CloudFront + S3. Re-embedding on every
    navigation tears down the chat and re-redeems URLs. A shell.html that never reloads, with only
    an inner <iframe> swapping, keeps the conversation alive on one per-session embed URL.

Best Practices Checklist

Identity & embedding
  • [ ] Embed the real registered user with GenerateEmbedUrlForRegisteredUser (real UserArn from roleName/sessionName).
  • [ ] Keep the request minimal: ExperienceConfiguration={'QuickChat': {}} + AllowedDomains only — identity comes solely from the ARN.
  • [ ] Treat the embed URL as single-use (5-min redemption, 10h session); mint fresh per frame load, never cache/log it.
  • [ ] Provision users/groups via IdP → SCIM → IDC; map groups to ADMIN_PRO/AUTHOR_PRO/READER_PRO (no per-user grants).
  • [ ] Grant agent access to groups with UpdateAgentPermissions; verify with DescribeAgent.
  • [ ] Auto-upgrade READER → READER_PRO only for chat-entitled users; budget ~$40/user/mo and reconcile to entitlement.
Row-level security (the centerpiece)
  • [ ] Build the two-column rules dataset (UserName → students primary key student_id); assert one UserName → exactly one row.
  • [ ] Attach via RowLevelPermissionDataSet (PermissionPolicy = GRANT_ACCESS, FormatVersion = VERSION_1).
  • [ ] Validate by impersonation: test as ≥2 real students (and one group-only user); confirm zero cross-student leakage regardless of phrasing.
  • [ ] Scope mentor discoverability via a GroupName = Enrolled-Students rule; let preferences filter which rows surface.
  • [ ] Confirm RLS resolves against the real IdP identity from IDC — nothing from the embedding layer influences filtering.
Data & performance
  • [ ] Connect to the RDBMS via the RDS connector over SSL inside a VPC.
  • [ ] Import into SPICE with a scheduled daily refresh; keep the schema minimal.
  • [ ] Pre-join into a flat view (e.g. MENTOR_PROFILE_FLAT).
  • [ ] Prefer Topics over Dataset Q&A; enable smart-mode fallback; add rich semantic metadata.
  • [ ] Add Lake Formation column-level controls as defense in depth.
Networking, frontend & SDK
  • [ ] Expose the embed API only through a PRIVATE API Gateway behind a VPC endpoint (aws:sourceVpce).
  • [ ] Serve the frontend from CloudFront + S3 over HTTPS; use the shell/iframe persistence pattern.
  • [ ] Register the embedding domain in both the Lambda AllowedDomains and the account-level allowlist.
  • [ ] Embed with createEmbeddingContext() + embedQuickChat(frameOptions, {fixedAgentArn}); pin the agent.
  • [ ] Configure per-feature controls at the agent level, not via SDK flags.
  • [ ] Standardize reasoning mode via URL params: defaultReasoningMode=SMART + showReasoningModeSelection=false; set web-search params for consistency. Remember SMART is the fresh-user default — "stuck on Advanced" is a saved preference the URL params override.

Reference Architecture

LayerComponentPurpose
Identity governanceIdP → SCIM → IAM Identity Center → QuickAuto-provisioned users/groups; single source of truth
PortalExisting student portal (web app)User authentication + UI
FrontendCloudFront + S3 (shell/iframe)Persistent chat across navigations
Embed mintingPRIVATE API Gateway (VPC endpoint) + LambdaReal user ARN, READER→READER_PRO, GenerateEmbedUrlForRegisteredUser
Access controlGroup→role mapping, agent permissions, user-based RLS rules datasetsKeyed to the real authenticated identity
Defense in depthLake Formation column-level controlsLimits which columns the service role can read
AI agentQuick Chat Agent (QuickChat)Mentor-matching intelligence
DataRDBMS (via Amazon RDS) → SPICE datasetsStudents dataset (PK student_id) + pre-joined MENTOR_PROFILE_FLAT
OptimizationTopics (pre-indexed)Sub-30s Q&A response
UXQuick Embedding SDK (embedQuickChat, fixedAgentArn)Seamless in-portal chat

This pattern applies to any organization building an identity-aware embedded UI on Amazon
Quick
— where an agent needs per-user data isolation on RDBMS Datasets
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article