For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Contact UsSign In
HomeIntegrationsGuidesBrand Assets
HomeIntegrationsGuidesBrand Assets
    • Overview
  • IAM Platforms
  • OIDC
    • Overview
    • Configuration
    • Integration
    • Best Practices
    • PKCE
  • SAML
    • Overview
    • Configuration
    • Integration
    • Best Practices
  • OAuth 2.0
    • Overview
    • Integration
    • PKCE
    • Error Codes
  • Shared Signals Framework
    • Registration and Transmission
  • Mobile SDK
    • Overview
    • Android
    • iOS
    • Video Demos
  • API
    • Applications API
    • Document Passback API
  • Learn More
      • Overview
      • Multi-Factor Authentication
      • Knowledge-Based Authentication
      • Fortified Identity
      • NIST IAL2
      • TEFCA Individual Access Services
    • Language Support
LogoLogo
Contact UsSign In
On this page
  • Overview
  • Authentication flow
  • Prerequisites
  • Environments
  • OIDC discovery endpoints
  • Configure your application
  • Register your application with ID.me
  • Redirect URIs
  • Configure ID.me as an OpenID Connect identity provider
  • Authorization request
  • Token exchange
  • Verification result types
  • OIDC identity token (id_token)
  • Required TEFCA IAS demographics
  • TEFCA IAS demographics that must be included if known
  • Validate the token
  • Test the integration
  • Security best practices
  • Troubleshooting
  • Token validation failures
  • Consent screen not appearing
  • Reference
Learn MoreDigital Wallet

TEFCA Individual Access Services (IAS) integration guide

Configure your application to support TEFCA Individual Access Services (IAS) with ID.me.

Was this page helpful?
Edit this page
Previous

Overview

Next
Built with

Overview

The Trusted Exchange Framework and Common Agreement (TEFCA) is a U.S. healthcare interoperability framework that enables individuals to securely access their own health records across disparate networks. ID.me supports the TEFCA Individual Access Services (IAS) exchange purpose, empowering patients to request and receive their health information through apps of their choice using NIST 800-63-3 Identity Assurance Level 2 (IAL2) identity proofing.

Intended audience
Developers and IAM administrators responsible for configuring federation between a TEFCA IAS application and ID.me.

What you will build
A TEFCA-compliant patient access workflow where ID.me serves as the Credential Service Provider (CSP) issuing IAL2-verified identity tokens to your IAS application.

Result
A patient logs into your app, verifies their identity via ID.me, and grants consent to retrieve their clinical records with a single IAS request across the TEFCA network.

Authentication flow

The following steps outline the TEFCA IAS authentication flow between the patient, your application, the Qualified Health Information Network (QHIN), and ID.me:

1

The patient initiates a login to your application

2

Your application redirects the patient to ID.me for identity verification, including the TEFCA IAS policy scope

3

The patient completes authentication and NIST IAL2 identity proofing at ID.me

4

The patient reviews and grants consent to share their verified identity attributes with your application

5

ID.me issues a signed OIDC identity token containing verified demographic claims

6

Your application relays the ID.me identity token to the QHIN as part of the IAS query

7

The QHIN validates the token against ID.me’s published JWKS endpoint and recognizes the patient’s verified identity and consent

8

The QHIN securely transfers the patient’s health records (USCDI v1 minimum) back to your application

Prerequisites

Before beginning this integration, ensure you have the following:

  • Communicate to your ID.me Solution Consultant that you intend to use the Individual Access token — an IAL2-level policy will be provisioned for your application
  • A registered OID (Object Identifier) registered with HL7, required before a production client can be created
  • A registered application capable of handling the Authorization Code Grant type
  • A publicly accessible redirect URI (HTTPS required in production)
  • Familiarity with OIDC flows, JWT validation, and token-based authentication concepts

Environments

ID.me provides two environments:

Sandbox

https://api.idmelabs.com/

Production

https://api.id.me/

All ID.me OIDC endpoints are derived from the base URL above. Replace the sandbox base URL with the production base URL in every endpoint you configure before going live.

OIDC discovery endpoints

EndpointSandboxProduction
OIDC Issuerhttps://api.idmelabs.com/oidchttps://api.id.me/oidc
Discovery documenthttps://api.idmelabs.com/oidc/.well-known/openid-configurationhttps://api.id.me/oidc/.well-known/openid-configuration
Authorization endpointhttps://api.idmelabs.com/oauth/authorizehttps://api.id.me/oauth/authorize
Token endpointhttps://api.idmelabs.com/oauth/tokenhttps://api.id.me/oauth/token
JWKS endpointhttps://api.idmelabs.com/oidc/jwkshttps://api.id.me/oidc/jwks
UserInfo endpointhttps://api.idmelabs.com/api/public/v3/attributes.jsonhttps://api.id.me/api/public/v3/attributes.json

Configure your application

Register your application with ID.me

Before configuring your identity provider settings, you must register your application with ID.me to obtain OAuth 2.0 credentials.

1

Contact your ID.me Solution Consultant and communicate that you intend to use the Individual Access token. Provide the following details:

  • Application name: The display name patients will see during the consent screen
  • OID: Your HL7-registered Object Identifier (required for production)
  • Redirect URIs: One or more HTTPS callback URLs your application will use after authentication (see Redirect URIs below)
  • Requested scopes: At minimum openid plus the TEFCA IAS policy scope handle (provided by your Solution Consultant)
  • Environment: Sandbox, production, or both
2

ID.me will provision an IAL2-level project and policy for your application, then return:

  • client_id: Your application’s unique identifier. This will either reflect your HL7 OID or an ID.me specific client ID.
  • client_secret: Your application’s secret credential (store securely — never expose in client-side code)
3

Store your credentials securely in your application’s secrets management system. You will use these in the token exchange step of the Authorization Code flow.

Redirect URIs

Redirect URIs must be pre-registered with ID.me. ID.me will reject any authorization request that specifies an unregistered redirect_uri.

Requirements:

  • Must use HTTPS in production (HTTP is permitted in sandbox for localhost only)
  • Must be an exact match — wildcard URIs are not supported
  • Mobile apps may use custom URI schemes (e.g., com.example.app://callback) if registered

Configure ID.me as an OpenID Connect identity provider

With your client_id and client_secret in hand, configure your application to initiate the Authorization Code flow against ID.me.

Authorization request

Direct the patient to ID.me’s authorization endpoint with the following parameters:

Example
$GET https://api.idmelabs.com/oauth/authorize
$ ?response_type=code
$ &client_id=IDME_CLIENT_ID
$ &redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fcallback
$ &scope=openid+YOUR_TEFCA_IAS_POLICY_SCOPE
$ &state=RANDOM_STATE_VALUE
$ &nonce=RANDOM_NONCE_VALUE
ParameterRequiredDescription
response_typeYesMust be code for Authorization Code flow
client_idYesYour ID.me specific client ID, not the HL7 OID
redirect_uriYesMust match a pre-registered URI exactly; URL-encode the value
scopeYesSpace-separated list including openid and your TEFCA IAS policy scope handle
stateYesRandom opaque value used to prevent CSRF attacks; validate on return
nonceRecommendedUnique per-session value embedded in the id_token; validate to prevent replay attacks

Upon completion of the verification flow, ID.me redirects the patient back to your redirect_uri with an authorization_code. Parse this code from the URL and use it to perform the token exchange.

Token exchange

Exchange the authorization code for tokens using the token endpoint:

Example
$curl --request POST \
> --url https://api.idmelabs.com/oauth/token \
> --header 'Content-Type: application/x-www-form-urlencoded' \
> --data-urlencode 'grant_type=authorization_code' \
> --data-urlencode 'code=AUTHORIZATION_CODE' \
> --data-urlencode 'redirect_uri=https://yourapp.example.com/callback' \
> --data-urlencode 'client_id=urn:oid:1.2.3.4.5.6' \
> --data-urlencode 'client_secret=YOUR_CLIENT_SECRET'
ParameterDescription
grant_typeMust be authorization_code
codeThe authorization code returned to your redirect URI
redirect_uriMust exactly match the URI used in the authorization request
client_idYour ID.me specific client ID, not the HL7 OID
client_secretYour application secret

Verification result types

The token response varies depending on whether identity verification was successful.

Successful verification — ID.me returns an access_token, id_token, and refresh_token. The id_token is only issued when the patient’s demographics have been fully validated to IAL2. Use the id_token to relay the patient’s identity to the QHIN.

Example
1{
2 "access_token": "eyJ...",
3 "token_type": "Bearer",
4 "expires_in": 300,
5 "id_token": "eyJ...",
6 "refresh_token": "eyJ..."
7}

OIDC identity token (id_token)

ID.me issues an id_token signed using RS256. The token payload follows standard OIDC claim names and includes TEFCA-required demographic attributes. The aud claim reflects your OID-formatted client_id.

Example
1{
2 "iss": "https://api.idmelabs.com/oidc",
3 "sub": "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789",
4 "aud": ["urn:oid:1.2.3.4.5.6"],
5 "iat": 1700000000,
6 "exp": 1700003600,
7 "auth_time": 1700000000,
8 "nonce": "RANDOM_NONCE_VALUE",
9 "jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
10 "given_name": "JANE",
11 "middle_name": "MARIE",
12 "family_name": "DOE",
13 "birthdate": "1985-04-12",
14 "gender": "F",
15 "email": "jane.doe@example.com",
16 "phone_number": "+15551234567",
17 "address": {
18 "country": "US",
19 "formatted": "123 MAIN ST, APT 4B, SPRINGFIELD, IL 62701 US",
20 "locality": "SPRINGFIELD",
21 "postal_code": "62701",
22 "region": "IL",
23 "street_address": "123 MAIN ST, APT 4B"
24 },
25 "historical_address": [
26 {
27 "formatted": "456 OAK AVE, CHICAGO, IL 60601",
28 "locality": "CHICAGO",
29 "postal_code": "60601",
30 "region": "IL",
31 "street_address": "456 OAK AVE"
32 }
33 ]
34}

The exact claim names returned depend on your ID.me policy configuration. Work with your ID.me Solution Consultant to confirm which attributes your policy handle returns and how they map to the TEFCA required demographics.

Required TEFCA IAS demographics

Per the Sequoia Project IAS SOP, the following patient demographics must be validated to IAL2 and present in the token:

AttributeOIDC ClaimNotes
Legal first namegiven_name
Legal last namefamily_name
Date of birthbirthdateYYYY-MM-DD format
AddressaddressA single object formatted as: “address”:{ “formatted”:”1060 West Addison Street, Chicago, IL 60613 USA”, “street_address”:”1060 West Addison Street”, “locality”:”Chicago”, “region”:”Illinois”, “postal_code”:”60613”, “country”:”USA” },
NicknamenicknameID.me does not currently support nickname and will return Unknown per IAS spec.

TEFCA IAS demographics that must be included if known

Per the Sequoia Project IAS SOP, the following patient demographics must be validated to IAL2 and present in the token if they are known:

AttributeOIDC ClaimNotes
Historical addresshistorical_addressAn object or array of objects formatted as: “historical_address”:{ “formatted”:”31 Spooner Street, Quahog, Rhode Island 02907”, “street_address”:”31 Spooner Street”, “locality”:”Quahog”, “region”:”Rhode Island”, “postal_code”:”02907”, “country”:”USA” },
Middle Namemiddle_name
NicknamenicknameID.me does not currently support nickname and will return Unknown per IAS spec.
Emailemail
Phonephone_number
SSNSSN
Last 4 of SSNSSN_Last_four_digits
Gendergender

Validate the token

Before relaying the identity token to a QHIN, validate it against ID.me’s public key. Fetch the JWKS from the endpoint below and use a standard JWT library to verify the token signature using the key matching the token’s kid header value.

Example
$GET https://api.idmelabs.com/oidc/jwks

When validating, confirm all of the following:

  • The token signature verifies against the JWKS public key
  • The iss claim matches ID.me’s issuer URI for the environment (sandbox or production)
  • The aud claim matches your registered client_id
  • The exp claim has not elapsed (token has not expired)
  • The iat claim is in the past
  • The nonce claim matches the value sent in your authorization request

Never relay an identity token to a QHIN without first completing full token validation. An invalid or expired token will be rejected by the QHIN and may expose your integration to replay attacks.

Test the integration

Use the ID.me sandbox environment (https://api.idmelabs.com/) to validate your integration end-to-end before promoting to production.

1

Initiate an authorization request

Do this from your application using your sandbox client_id (OID format) and your TEFCA IAS policy scope. Confirm the redirect correctly lands on the ID.me sandbox login page.

2

Complete identity verification

Use the ID.me sandbox test credentials provided by your Solution Consultant. The sandbox simulates the full IAL2 proofing flow without requiring real identity documents.

3

Inspect the token response

Confirm that id_token and refresh_token are present, indicating a successful verification. Decode the id_token (e.g., at jwt.io) and verify:

  • iss matches https://api.idmelabs.com/oidc
  • aud matches your OID-formatted client_id
  • All required TEFCA demographics are present (name, DOB, address claims)
  • The nonce matches the value sent in the authorization request
4

Validate the token signature

Fetch the JWKS from https://api.idmelabs.com/oidc/jwks and confirming the signature verifies against the key matching the token’s kid header value.

5

Submit a test IAS query

Send this to your QHIN’s sandbox or test environment with the token relayed in the appropriate format (SAML attribute or tefca_ias FHIR extension). Confirm the QHIN accepts the token and returns a successful query response.

6

Test a failed verification

Confirm your application handles an unsuccessful response (no id_token in the token response) gracefully, without attempting to relay a non-existent token to the QHIN.

7

Test edge cases

Test multiple cases including expired tokens, mismatched nonce values, and historical_address arrays with multiple entries, to confirm your parsing and error handling behaves as expected.

Token expiry defaults to 5 minutes (expires_in: 300). Request a fresh token for each IAS query rather than caching tokens across sessions.

Security best practices

When extracting claims from the identity token, follow these best practices to maintain a secure and reliable integration:

Validate the token — Always validate the token before extracting claims. Verify the signature, and confirm the exp and iat claims ensure the token is still valid. Never relay an unvalidated token.

Check the audience (aud) — Confirm the aud claim matches your client_id. This ensures the token was issued for your application and not for a different relying party.

Verify the issuer (iss) — Ensure iss matches ID.me’s issuer URI for the active environment. Tokens from the sandbox issuer must never be accepted in production and vice versa.

Handle claims securely — Extract only the claims your application needs to minimize data exposure. Treat demographic attributes (email, phone, address) as sensitive data and ensure compliance with applicable privacy regulations.

Use the state parameter — Always generate a unique state value per session in your authorization request and validate it on return. This prevents cross-site request forgery (CSRF) attacks.

Use the nonce parameter — Embed a unique nonce in the authorization request and validate it in the returned id_token. This prevents token replay attacks.

Do not cache JWKS keys indefinitely — Rotate your cached public keys periodically by re-fetching the JWKS endpoint. ID.me may rotate signing keys, and stale cached keys will cause signature validation failures.

Log and monitor — Log token validation attempts and monitor for unusual patterns, such as repeated validation failures or tokens with unexpected aud or iss values, which may indicate an attack.

Troubleshooting

Token validation failures

If the QHIN rejects the identity token, check the following:

SymptomLikely causeResolution
Signature verification failedStale cached JWKS keysRe-fetch JWKS from ID.me’s endpoint; do not cache keys indefinitely
iss mismatchEnvironment mismatch (sandbox vs. production)Ensure token issuer and QHIN environment match
aud mismatchToken issued for a different clientConfirm your OID-formatted client_id matches what is registered with ID.me
id_token absent from token responseVerification was unsuccessfulCheck verification session endpoint for failure reason; do not proceed with QHIN query

Consent screen not appearing

If patients are not presented with a consent screen to share identity attributes, confirm that your authorization request includes the correct TEFCA IAS policy scope handle. The scope drives which attributes are requested and triggers the consent screen. Contact your ID.me Solution Consultant to verify your policy scope configuration.

Reference

  • Sequoia Project IAS Implementation SOP v2.0
  • IAS Provider Requirements SOP v2.1
  • Facilitated FHIR Implementation SOP
  • TEFCA Guide – September 2024
  • HL7 OID Registry
  • ID.me OIDC Overview