← Blog
Field note

SMART Backend Services: xác thực server và AI agent với FHIR

Thien Nguyen · Nov 11, 2026

SMART Backend Services là cách chuẩn để một server, hay tầng công cụ của AI agent, gọi FHIR API khi không có người dùng: đăng ký public key (JWKS), ký một JWT hết hạn trong vòng 5 phút, đổi lấy access token chỉ nên sống tối đa 300 giây, và xin các scope system/ hẹp theo SMART v2, không bao giờ xin system/*.cruds.

Backend services từng là chuyện ngách: export ban đêm và phân tích theo quần thể bệnh nhân. Năm 2026 nó có mặt trong hầu hết roadmap tích hợp, vì AI agent, tự động hóa prior authorization và trao đổi dữ liệu payer–provider đều cần truy cập server-to-server. Quy định HTI-1 của ONC đặt SMART App Launch 2.0.0 làm mặt bằng cho API (g)(10) đạt chứng nhận từ 31/12/2025, và bản đặc tả đang công bố là SMART App Launch v2.2.0. Bài này dành cho kỹ sư và CTO phải làm đúng: giao thức, thiết kế scope, quản lý khóa, và các kiểu hỏng riêng của AI agent.

SMART on FHIR Backend Services là gì?

Đó là profile SMART cho các client chạy tự động hoặc bán tự động, với quyền truy cập đã được FHIR server cấp trước. Nó dùng OAuth 2.0 client-credentials grant với xác thực client bất đối xứng (public key). Không có đăng nhập người dùng, không có redirect.

Đặc tả nói profile này phù hợp khi client chạy không cần ủy quyền ở mức người dùng, hỗ trợ xác thực bất đối xứng, và không có lý do bắt buộc nào để người dùng phải ủy quyền lúc chạy. Dùng điển hình: bulk export, pipeline dữ liệu, job theo lịch, và phía server của AI agent làm việc theo hàng đợi thay vì thay mặt một bác sĩ đang đăng nhập.

EHR launch / standalone launchBackend Services
Ai ủy quyềnMột người dùng (bác sĩ hoặc bệnh nhân) lúc chạyQuản trị viên FHIR server, cấp từ trước
GrantAuthorization code (+ PKCE)Client credentials với JWT assertion đã ký
Scope điển hìnhuser/ hoặc patient/system/
Audit quy cho aiNgười dùng đang đăng nhậpClient (thường được EHR ánh xạ vào một user dịch vụ)
Phù hợp nhất choApp và assistant tương tác trong workflow của bác sĩJob batch, export, worker theo hàng đợi, tầng công cụ của agent

Luồng lấy token của Backend Services chạy thế nào?

Bốn bước: đọc .well-known/smart-configuration của server, dựng và ký một JWT xác thực bằng private key, POST nó tới token endpoint với grant_type=client_credentials, rồi gọi FHIR API bằng bearer token sống ngắn nhận về.

  1. Discovery. Đọc token_endpoint, token_endpoint_auth_methods_supported (phải có private_key_jwt) và token_endpoint_auth_signing_alg_values_supported (phải có ít nhất một trong RS384 hoặc ES384), theo trang xác thực client bất đối xứng.
  2. JWT xác thực. Header: alg, kid (duy nhất trong JWK Set của bạn), typ: JWT, jku tùy chọn. Claim: iss và sub = client_id, aud = URL token, exp không quá năm phút trong tương lai, và một jti duy nhất.
  3. Xin token. POST dạng form với scope, grant_type=client_credentials, client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer và client_assertion.
  4. Dùng token. Phản hồi có access_token, token_type: bearer, expires_in và scope. Scope được cấp có thể khác scope đã xin, nên hãy kiểm tra trước khi chạy job.

Về thời hạn, đặc tả nói rõ access token phải sống ngắn, expires_in không nên vượt 300, tức năm phút. Hãy xin token mới khi cần thay vì cache một token cả tiếng.

Bốn bước của SMART Backend Services: 1 tìm token endpoint và thuật toán hỗ trợ (private_key_jwt với RS384 hoặc ES384); 2 ký JWT với iss và sub là client_id, aud là URL token, exp tối đa 5 phút tới và jti duy nhất; 3 POST yêu cầu client_credentials với scope system hẹp; 4 kiểm tra scope được cấp và dùng token tối đa 300 giây.
Không người dùng, không redirect: JWT đã ký vào, token năm phút ra.

Nên dùng thuật toán ký và khóa nào?

Dùng ES384 hoặc RS384, công bố qua JWKS URL với kid ổn định cho mỗi khóa, cặp khóa riêng cho từng môi trường, và quy trình xoay vòng thêm khóa mới trước khi dùng. Hãy kiểm tra quy tắc riêng của từng EHR, vì chúng khác nhau.

Đặc tả SMART yêu cầu server hỗ trợ ít nhất một trong RS384 hoặc ES384. Các bản triển khai của EHR thêm ràng buộc riêng. Ví dụ, đặc tả OAuth 2.0 của Epic chấp nhận RS256, RS384 và RS512 cho mọi confidential client, ES256 và ES384 chỉ cho client đăng ký JWK Set URL, yêu cầu jti tối đa 151 ký tự, và không chấp nhận JWKS URL non-production làm URL production cho app mới.

Quy tắc quản lý khóa chúng tôi áp dụng

  • Dùng JWKS URL thay vì upload tĩnh. Xoay khóa khi đó chỉ là đổi cấu hình, không phải mở ticket. Đặc tả nói server không được cache JWKS lâu hơn header cache-control của client, nên hãy đặt header này có chủ đích.
  • Private key nằm trong KMS hoặc HSM, không bao giờ trong biến môi trường hay container image. Ký thông qua API của KMS.
  • Xoay khóa ba bước: công bố public key mới, chờ hết thời gian cache JWKS, chuyển sang ký bằng khóa mới, rồi gỡ khóa cũ sau khi qua thời hạn token dài nhất.
  • Mỗi môi trường và mỗi ranh giới tenant một cặp khóa. Nếu production và staging dùng chung khóa, một máy staging bị xâm nhập có thể mạo danh production.
  • Kỷ luật đồng hồ. Với cửa sổ 5 phút cho exp, lệch đồng hồ vài phút sẽ làm xác thực hỏng lúc được lúc không. Chạy NTP và ghi log nội dung lỗi server trả về.
Bốn con số của SMART Backend Services: exp của JWT không quá 5 phút tới; thời hạn access token không nên vượt 300 giây; server phải hỗ trợ ít nhất một trong RS384 hoặc ES384, Epic còn nhận RS256, RS512 và ES256; Epic giới hạn jti 151 ký tự và không cho dùng lại khi JWT còn hiệu lực.
Cửa sổ ngắn khiến lệch đồng hồ và dùng lại jti thành nguyên nhân 401 hàng đầu.

Thiết kế scope SMART v2 cho backend service thế nào?

Xin tập scope nhỏ nhất ở mức resource theo cú pháp v2 (create, read, update, delete, search), tách đọc và ghi ra các client khác nhau khi có thể, và chỉ dùng scope chi tiết có tham số truy vấn ở chỗ server ghi rõ là hỗ trợ.

Theo đặc tả scope của SMART:

  • Quyền v2. system/Observation.rs nghĩa là đọc và tìm kiếm Observation. Scope v1 quy đổi: .read → .rs, .write → .cud, .* → .cruds.
  • Scope chi tiết. Thêm hậu tố truy vấn để thu hẹp, ví dụ patient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory chỉ cho kết quả xét nghiệm.
  • Tính năng thử nghiệm. Đặc tả xếp search modifier, tham số nối chuỗi (chaining) và _filter trong scope vào nhóm thử nghiệm, kể cả khi server có hỗ trợ. Đừng xây mô hình bảo mật trên chúng.
  • Batch và transaction. Được kiểm tra dựa trên từng request bên trong, nên transaction không lách được scope.

Một mẫu scope qua được vòng đánh giá bảo mật

ClientScopeVì sao tách
Reader (pipeline, ngữ cảnh cho agent)system/Patient.rs system/Encounter.rs system/Condition.rs system/Observation.rsĐa số job chỉ đọc; lộ token thì lộ dữ liệu nhưng không sửa được gì
Writer (chỉ hành động đã duyệt)system/DocumentReference.c system/Task.cuĐường ghi nhỏ, có audit, chỉ được gọi sau khi người duyệt
Bulk exporterScope .rs cho đúng các loại resource được exportJob chạy lâu; tách riêng giới hạn tốc độ và khóa

Tên resource ở đây chỉ để minh họa. Hãy dùng những gì từng EHR công bố là hỗ trợ cho truy cập system/, vì chúng khác nhau theo vendor và phiên bản.

AI agent nên dùng Backend Services hay token theo ngữ cảnh người dùng?

Dùng token theo ngữ cảnh người dùng (EHR launch) khi agent làm việc thay một bác sĩ đang đăng nhập, để quyền truy cập và audit đi theo người đó. Dùng Backend Services cho việc chạy theo hàng đợi mà không do một người cụ thể kích hoạt, và giữ token trong tầng công cụ mà model không nhìn thấy.

Rủi ro khi đưa backend token cho agent rất đơn giản: token system/ thấy mọi bệnh nhân mà client được cấp quyền, và audit log của EHR quy lệnh gọi cho client, không cho người đã đặt câu hỏi với agent. Một lần prompt injection hay một lỗi lập kế hoạch khi đó thành sự cố lộ dữ liệu cấp quần thể. Các lớp kiểm soát chúng tôi đặt trước mọi backend token mà agent có thể chạm tới:

  • Token broker. Model gọi tool; tool gọi broker; chỉ broker giữ khóa và token. Model không bao giờ thấy token hay URL FHIR thô.
  • Gắn bệnh nhân theo từng request. Tool chỉ nhận ID bệnh nhân từ hồ sơ hay mục hàng đợi đang xử lý, và từ chối truy vấn ngoài phạm vi đó.
  • Thao tác theo allow-list. Mỗi tool ánh xạ vào truy vấn FHIR cố định. Không nhận chuỗi tìm kiếm tự do từ model.
  • Người duyệt trước khi ghi và trước khi bất cứ thứ gì rời khỏi tổ chức.
  • Audit trail của riêng bạn ghi người yêu cầu, lượt chạy của agent, lệnh gọi tool và request ID của FHIR, vì log của EHR chỉ thấy client.
  • Dữ liệu tối thiểu cần thiết cho model: có phải lấy rộng thì lấy, nhưng chỉ chuyển cho model các trường mà việc đó cần.

Nếu bạn đưa công cụ FHIR cho agent qua MCP, các quy tắc trên áp dụng cho MCP server: nó giữ thông tin xác thực, thực thi allow-list và ghi log mọi lệnh gọi. Xem bài phát triển MCP server và checklist bảo mật AI agent.

Backend Services hay hỏng ở đâu nhất?

Lệch đồng hồ, dùng lại jti, sai aud, bất ngờ về cache JWKS khi xoay khóa, cho rằng scope được cấp bằng scope đã xin, và cache access token quá thời hạn. Mỗi lỗi sinh ra các lỗi 401 lúc có lúc không, rất khó tái hiện.

  • Sai aud: phải là URL của token endpoint. Một số server cho thêm audience; ví dụ Epic cho quản trị viên phía khách hàng thêm audience URL vào allow-list.
  • Dùng lại jti: server bắt buộc kiểm tra jti chưa từng xuất hiện với cùng issuer trong thời hạn JWT. Retry một request lỗi bằng đúng JWT cũ sẽ hỏng vì lý do này. Mỗi lần thử hãy tạo JWT mới.
  • Scope bị hạ ngầm: scope trong phản hồi có thể hẹp hơn đã xin. Thiếu scope bắt buộc thì dừng (fail closed).
  • Cấu hình theo từng khách hàng: EHR có thể cần cấu hình ở cấp site trước khi backend client chạy được, như ánh xạ vào một user dịch vụ để audit. Chạy được trên sandbox không nói lên gì về bước đó.
  • Giới hạn tốc độ ở token endpoint: xin token mới cho mỗi lệnh gọi FHIR có thể chạm giới hạn. Hãy dùng lại token trong thời hạn (ngắn) của nó.

Kiểm thử tích hợp Backend Services trước go-live thế nào?

Chủ động kiểm thử các đường lỗi: JWT hết hạn, jti dùng lại, sai kid, khóa đã xoay, scope bị thu hẹp, client bị thu hồi, và 429 từ token endpoint. Sau đó chạy cùng bộ test trên môi trường non-production của từng khách hàng, không chỉ trên sandbox của vendor.

Với tính năng AI, thêm một bộ đánh giá chứng minh agent không bao giờ xin dữ liệu ngoài bệnh nhân được gắn, không bao giờ gọi tool ghi khi chưa có bản ghi phê duyệt, và xuống cấp an toàn khi token broker từ chối. Bộ đánh giá đó thuộc về CI, không phải một lần pentest. Bài kiểm thử LLM cho ngành chịu quản lý mô tả cách chúng tôi xây các bộ test này. Với bulk export dùng cùng cơ chế xác thực, xem bulk FHIR export cho phân tích và AI.

Bản thân SMART Backend Services có đủ để tuân thủ HIPAA không?

Không. Nó là cơ chế xác thực và phân quyền. HIPAA vẫn đòi BAA với mọi business associate xử lý PHI, kiểm soát truy cập, kiểm soát audit và nguyên tắc dùng tối thiểu cần thiết, và những thứ đó nằm trong kiến trúc của bạn, không nằm trong token.

Một backend client có scope gọn giúp bạn chứng minh phần tối thiểu cần thiết và kiểm soát truy cập. Bạn vẫn cần logging, lưu trữ, ứng phó sự cố và thỏa thuận với nhà cung cấp cloud, nhà cung cấp model và mọi bên khác trên đường đi của dữ liệu. Xem bài AI agent tuân thủ HIPAA cho đầy đủ các lớp kiểm soát.

BeevR làm việc này thế nào

Chúng tôi xây tích hợp backend theo cách mà người đánh giá bảo mật mong đợi: khóa công bố qua JWKS và giữ trong KMS của cloud, cặp khóa riêng cho từng môi trường, xoay khóa bằng script, tách client đọc và client ghi, token broker đứng trước mọi thành phần AI, và audit trail ghi tên người đứng sau mỗi hành động của agent. Chúng tôi kiểm thử các đường lỗi trong CI và trên môi trường non-production của khách hàng bạn. BeevR ký BAA với tư cách business associate, AI model có thể chạy trong chính tài khoản AWS của bạn theo AWS BAA, và bạn sở hữu source code và IP từ ngày đầu.

Đội senior do founder dẫn dắt ở Hà Nội đang vận hành một EHR multi-tenant ở bốn phòng khám tại Mỹ với khoảng 300 bệnh nhân mỗi ngày, và bạn xem demo chạy được mỗi thứ Sáu. Công việc chạy theo các giai đoạn phạm vi cố định, giá cố định từ $10K mỗi giai đoạn. Xem dịch vụ tích hợp EHR và AI agent tuân thủ HIPAA.

Đang nối một server hay AI agent vào EHR? Đặt lịch gọi 30 phút, chúng tôi sẽ cùng bạn rà luồng xác thực và thiết kế scope.