@healthcloudai/hc-login-connector
Healthcheck Login Connector
This library provides a tenant-aware client for patient registration, onboarding, authentication, password reset flows, token refresh, authenticated patient context retrieval, and local auth helper methods.
The connector is built on top of the shared Healthcheck HTTP layer, and the examples
below follow the current behavior implemented in src/client.ts.
Features
- Patient registration with tenant-scoped request payloads
- Generic onboarding step submission through
submitOnboardingStep(...) - Convenience helpers for email verification and SMS verification steps
- Convenience helpers for health profile and address onboarding steps
- Patient login with in-memory access, refresh, and ID token storage
- Password reset initiation and password reset confirmation
- Access token, ID token, tenant, and base URL helper methods
- Token refresh using the stored refresh token
- Authenticated patient header retrieval through
getPatientHeader() - Built on the shared Healthcheck HttpClient layer
Installation
npm install @healthcloudai/hc-login-connector \
@healthcloudai/hc-httpImport
import { HCLoginClient } from "@healthcloudai/hc-login-connector";
import { FetchClient } from "@healthcloudai/hc-http";Usage
Configuration
Call configure() before any other method.
It stores the tenant configuration locally on the client instance, and the same
configured client should be reused across registration, onboarding, login, refresh,
and authenticated calls.
const httpClient = new FetchClient();
const loginClient = new HCLoginClient(httpClient);
loginClient.configure("test-tenant", "dev");
// The current source signature also accepts an optional region argument:
// loginClient.configure("test-tenant", "dev", "region-code");Full API request
configure() does not send an HTTP request.
The configuration example above updates local client state only.
API response
configure() does not receive an API response.
It stores the tenant configuration locally for later requests.
API Key
Use setApiKey(...) to include an API key header with requests made by HCLoginClient.
const apiKey = process.env.HEALTHCLOUD_API_KEY;
if (!apiKey) {
throw new Error("HEALTHCLOUD_API_KEY is required.");
}
loginClient.setApiKey("x-api-key", apiKey);The first argument is the header name and the second argument is the API key value. After it is configured, the API key header is included automatically with registration, onboarding, login, token refresh, password reset, and authenticated patient header requests.
If your environment does not require an API key, you can skip this step.
Methods
Get Base URL
Public signature: loginClient.getBaseUrl()
Returns the base URL derived from the current configuration.
const baseUrl = loginClient.getBaseUrl();Full API request
getBaseUrl() does not send an HTTP request.
The usage example above reads the value from local state.
API response
getBaseUrl() returns the currently configured base URL from local state.
https://dev-api-healthcheck.healthcloud-services.com
Get Tenant ID
Public signature: loginClient.getTenantId()
Returns the tenant ID currently stored by configure(...).
const tenantId = loginClient.getTenantId();Full API request
getTenantId() does not send an HTTP request.
The usage example above reads the value from local state.
API response
getTenantId() returns the configured tenant ID from local state.
test-tenant
Submit Onboarding Step
Public signature: loginClient.submitOnboardingStep(step, user, data?, language?)
This is the step-driven onboarding API.
The selected step determines the final shape of Data.User, and TenantID is
injected internally from configure(...).
Callers should provide only the fields relevant to the selected step.
Supported steps:
EMAIL_VERIFYRESEND_EMAIL_VERIFYRESEND_SMS_VERIFYSMS_VERIFYSAVE_HEALTH_PROFILESAVE_ADDRESS
await loginClient.submitOnboardingStep(
"SAVE_HEALTH_PROFILE",
{
Email: "john.smith@example.com",
FirstName: "John",
LastName: "Smith",
BirthDate: "1990-01-01",
Gender: "male",
Race: "White",
Ethnicity: "Not Hispanic or Latino",
Status: 0,
Sex: "Male"
},
"",
"en"
);Full API request
Request sent for the usage example above:
{
"Data": {
"Data": "",
"Step": "SAVE_HEALTH_PROFILE",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"FirstName": "John",
"LastName": "Smith",
"BirthDate": "1990-01-01",
"Gender": "male",
"Sex": "Male",
"Status": 0,
"Race": "White",
"Ethnicity": "Not Hispanic or Latino"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Register
Public signature: loginClient.register(email, password, firstName?, lastName?, options?)
Registers a patient for the configured tenant.
TenantID is injected internally from configure(...).
options.attributes can be used to pass arbitrary additional custom fields.
Every key/value pair from options.attributes is forwarded into User.Attributes.
This is the extension point for arbitrary extra registration fields, so the module
does not need to know those field names in advance.
All values inside options.attributes / User.Attributes should be sent as
strings. If a field needs to contain multiple values, serialize those values into
one string value, such as a comma separated list or another separator-separated
list expected by the integration.
isOTP is a dedicated boolean option that controls whether User.Attributes.VERIFY_EMAIL_CODE is included in the registration payload, depending on whether email verification should be handled through an OTP code.
- If
isOTPistrue, the client sendsVERIFY_EMAIL_CODE: "true". - If
isOTPisfalseor omitted,VERIFY_EMAIL_CODEis not sent.
OTP-based registration
Use this when email verification should be handled through an OTP code. In this case, isOTP should be true.
await loginClient.register(
"john.smith@example.com",
"ExamplePassword123!",
"John",
"Smith",
{
isOTP: true,
attributes: {
"ReferralSource": "Friend"
}
}
);Full API request
Request sent for the OTP example above:
{
"Data": {
"TenantID": "test-tenant",
"Credentials": {
"Email": "john.smith@example.com",
"Password": "ExamplePassword123!"
},
"User": {
"FirstName": "John",
"LastName": "Smith",
"Email": "john.smith@example.com",
"Attributes": {
"VERIFY_EMAIL_CODE": "true",
"ReferralSource": "Friend"
}
}
}
}Link-based registration
Use this when email verification should be handled through an email link. In this case, isOTP should be omitted or false.
await loginClient.register(
"john.smith@example.com",
"ExamplePassword123!",
"John",
"Smith"
);Effective request body:
{
"Data": {
"TenantID": "test-tenant",
"Credentials": {
"Email": "john.smith@example.com",
"Password": "ExamplePassword123!"
},
"User": {
"FirstName": "John",
"LastName": "Smith",
"Email": "john.smith@example.com",
"Attributes": {}
}
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Notes:
TenantIDis taken from the configured client instance.attributesis the extension point for arbitrary additional registration fields.- The module does not need to know custom attribute names in advance.
- All
attributesvalues should be strings. Multi-value attributes should be serialized into one string value, such as a comma separated list or another integration-specific separator-separated list. isOTPtakes precedence over any manually providedVERIFY_EMAIL_CODEinsideattributes.
Register Full
Public signature: loginClient.registerFull(options?)
Registers a patient for the configured tenant using the richer registration payload.
TenantID is injected internally from configure(...).
isOTP behaves the same way as in register(...):
when enabled, the client injects VERIFY_EMAIL_CODE: "true" into User.Attributes.
OTP-based registration
Use this when email verification should be handled through an OTP code. In this case, isOTP should be true.
await loginClient.registerFull({
email: "john.smith@example.com",
password: "ExamplePassword123!",
firstName: "John",
lastName: "Smith",
phone: "+15555550123",
birthDate: "1990-01-01",
gender: "Male",
middleName: "Test",
race: "Other",
ethnicity: "Other",
sex: "Male",
genderIdentity: "Male",
status: 0,
language: "en",
isOTP: true,
attributes: {
source: "sdk-test"
},
address: {
StreetAndNumber: "123 Test St",
Extension: "Apt 4",
City: "Springfield",
State: "CA",
PostalCode: "90210",
Country: "US"
}
});Full API request
Request sent for the usage example above:
{
"Data": {
"TenantID": "test-tenant",
"Credentials": {
"Email": "john.smith@example.com",
"Password": "ExamplePassword123!",
"TenantID": "test-tenant",
"Language": "en"
},
"User": {
"FirstName": "John",
"LastName": "Smith",
"Email": "john.smith@example.com",
"Phone": "+15555550123",
"BirthDate": "1990-01-01",
"Gender": "Male",
"MiddleName": "Test",
"Race": "Other",
"Ethnicity": "Other",
"Sex": "Male",
"GenderIdentity": "Male",
"Status": 0,
"Address": {
"StreetAndNumber": "123 Test St",
"Extension": "Apt 4",
"City": "Springfield",
"State": "CA",
"PostalCode": "90210",
"Country": "US"
},
"Attributes": {
"source": "sdk-test",
"VERIFY_EMAIL_CODE": "true"
}
}
}
}Link-based registration
Use this when email verification should be handled through an email link. In this case, isOTP should be omitted or false.
await loginClient.registerFull({
email: "john.smith@example.com",
password: "ExamplePassword123!",
firstName: "John",
lastName: "Smith"
});Effective request body:
{
"Data": {
"TenantID": "test-tenant",
"Credentials": {
"Email": "john.smith@example.com",
"Password": "ExamplePassword123!",
"TenantID": "test-tenant"
},
"User": {
"FirstName": "John",
"LastName": "Smith",
"Email": "john.smith@example.com",
"Attributes": {}
}
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Verify Email
Public signature: loginClient.verifyEmail(email, code, language?, options?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides email, code, an optional language, and optional
verification settings.
VERIFY_EMAIL_CODE handling is aligned with the register(...) method behavior:
when email verification should be handled through an OTP code, the client sends
VERIFY_EMAIL_CODE: "true" inside User.Attributes.
- If
options.isOTPistrue, the client sendsVERIFY_EMAIL_CODE: "true". - The value is sent as a string inside
User.Attributes, matching theregister(...)method behavior whenisOTPistrue. - If
options.isOTPisfalseor omitted,VERIFY_EMAIL_CODEis not sent. - Calling
verifyEmail(...)withoutoptionskeeps OTP email verification disabled by default.
OTP-based email verification
Use this when email verification should be handled through an OTP code. In this case, options.isOTP should be true.
await loginClient.verifyEmail(
"john.smith@example.com",
"123456",
"en",
{
isOTP: true
}
);Full API request
Request sent for the OTP example above:
{
"Data": {
"Data": "123456",
"Step": "EMAIL_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Attributes": {
"VERIFY_EMAIL_CODE": "true"
}
},
"Language": "en"
}
}Link-based email verification
Use this when email verification should be handled through an email link. In this case, options.isOTP should be omitted or false.
await loginClient.verifyEmail(
"john.smith@example.com",
"123456",
"en"
);Effective request body:
{
"Data": {
"Data": "123456",
"Step": "EMAIL_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Resend Email Verify
Public signature: loginClient.resendEmailVerify(email, language?, options?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides email, an optional language, and optional verification
settings.
VERIFY_EMAIL_CODE handling is aligned with the register(...) method behavior:
when email verification should be handled through an OTP code, the client sends
VERIFY_EMAIL_CODE: "true" inside User.Attributes.
- If
options.isOTPistrue, the client sendsVERIFY_EMAIL_CODE: "true". - The value is sent as a string inside
User.Attributes, matching theregister(...)method behavior whenisOTPistrue. - If
options.isOTPisfalseor omitted,VERIFY_EMAIL_CODEis not sent. - Calling
resendEmailVerify(...)withoutoptionskeeps OTP email verification disabled by default.
OTP-based resend
Use this when email verification should be handled through an OTP code. In this case, options.isOTP should be true.
await loginClient.resendEmailVerify(
"john.smith@example.com",
"en",
{
isOTP: true
}
);Full API request
Request sent for the OTP example above:
{
"Data": {
"Data": "",
"Step": "RESEND_EMAIL_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Attributes": {
"VERIFY_EMAIL_CODE": "true"
}
},
"Language": "en"
}
}Link-based resend
Use this when email verification should be handled through an email link. In this case, options.isOTP should be omitted or false.
await loginClient.resendEmailVerify(
"john.smith@example.com",
"en"
);Effective request body:
{
"Data": {
"Data": "",
"Step": "RESEND_EMAIL_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Resend SMS Verify
Public signature: loginClient.resendSmsVerify(email, phone, language?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides email, phone, and an optional language.
await loginClient.resendSmsVerify(
"john.smith@example.com",
"+15555550123",
"en"
);Full API request
Request sent for the usage example above:
{
"Data": {
"Data": "",
"Step": "RESEND_SMS_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Phone": "+15555550123"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Verify SMS
Public signature: loginClient.verifySms(email, phone, code, language?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides email, phone, code, and an optional language.
await loginClient.verifySms(
"john.smith@example.com",
"+15555550123",
"123456",
"en"
);Full API request
Request sent for the usage example above:
{
"Data": {
"Data": "123456",
"Step": "SMS_VERIFY",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Phone": "+15555550123"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Save Health Profile
Public signature: loginClient.saveHealthProfile(profile, language?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides the SAVE_HEALTH_PROFILE input fields, such as Email,
FirstName, LastName, BirthDate, Gender, Race, Ethnicity, Status,
and Sex.
await loginClient.saveHealthProfile({
Email: "john.smith@example.com",
FirstName: "John",
LastName: "Smith",
BirthDate: "1990-01-01",
Gender: "male",
Race: "White",
Ethnicity: "Not Hispanic or Latino",
Status: 0,
Sex: "Male"
});Full API request
Request sent for the usage example above:
{
"Data": {
"Data": "",
"Step": "SAVE_HEALTH_PROFILE",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"FirstName": "John",
"LastName": "Smith",
"BirthDate": "1990-01-01",
"Gender": "male",
"Sex": "Male",
"Status": 0,
"Race": "White",
"Ethnicity": "Not Hispanic or Latino"
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Save Address
Public signature: loginClient.saveAddress(email, address, language?)
Convenience wrapper around submitOnboardingStep(...).
The caller provides email, an Address, and an optional language.
await loginClient.saveAddress("john.smith@example.com", {
StreetAndNumber: "123 Test St",
Extension: null,
City: "Springfield",
State: "CA",
PostalCode: "90210",
Country: "US"
});Full API request
Request sent for the usage example above:
{
"Data": {
"Data": "",
"Step": "SAVE_ADDRESS",
"User": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Address": {
"StreetAndNumber": "123 Test St",
"Extension": null,
"City": "Springfield",
"State": "CA",
"PostalCode": "90210",
"Country": "US"
}
},
"Language": "en"
}
}API response
Status:
200
{
"Data": "",
"ErrorMessage": null,
"IsOK": true
}Login
Public signature: loginClient.login(email, password)
login(...) accepts only email and password.
The client builds the login Data payload internally, and stores the
returned tokens in memory.
On tenants that require onboarding completion, login may depend on the relevant
onboarding steps already being finished.
await loginClient.login(
"john.smith@example.com",
"ExamplePassword123!"
);Full API request
Request sent for the full payload usage example above:
{
"Data": {
"Email": "john.smith@example.com",
"Password": "ExamplePassword123!",
"TenantID": "test-tenant"
}
}API response
Status:
200
{
"Data": {
"Email": "john.smith@example.com",
"RefreshToken": "eyJ_refresh_token_example",
"AccessToken": "eyJ_access_token_example",
"IDToken": "eyJ_id_token_example",
"EHR": "fhir",
"ErrorMessage": null,
"HasInsurance": false,
"HasIDCard": false,
"HasSelfie": false,
"Attributes": {
"EHR": "fhir",
"Type": "PATIENT"
},
"ID": "john.smith@example.com",
"TenantID": "test-tenant",
"Expiration": "2030-01-01T00:00:00.000Z",
"Type": 0
},
"ErrorMessage": null,
"IsOK": true
}Reset Password
requestPasswordReset supports both OTP-based and link-based reset initiation
flows.
isOTP is optional. When it is true, the client includes
IsPasswordResetWithOTP: true in the API request. When false or omitted, the
backend field is not sent at all.
OTP-based password reset initiation
Use this when the password reset flow should be handled through an OTP code.
In this case, isOTP should be true.
await loginClient.requestPasswordReset("john.smith@example.com", true);Full API request
{
"Data": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"IsPasswordResetWithOTP": true
}
}Link-based password reset initiation
Use this when the password reset flow should be handled from an email link.
In this case, isOTP should be omitted by passing false or
leaving the second argument out.
await loginClient.requestPasswordReset("john.smith@example.com", false);Effective request body:
{
"Data": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant"
}
}Authorization: Bearer eyJ_id_token_example may also be included when an ID token
is already stored.
API response
Status:
200
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}Reset Password Confirm
confirmPasswordReset supports both OTP-based and link-based confirmation
flows.
If isOTP is true, Code is required. If isOTP is not true, Token is
required. The client maps isOTP: true to IsPasswordResetWithOTP: true in the
API request. For the link-based flow, the frontend is responsible for taking
the token from the password reset email link and passing that token in the
payload.
OTP-based password reset confirmation
Use this when the password reset flow was started with OTP. In this case,
isOTP should be true and Code should contain the final
reset code.
await loginClient.confirmPasswordReset({
Email: "john.smith@example.com",
Password: "ExamplePassword123!",
isOTP: true,
Code: "123456"
});Request body:
{
"Data": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Password": "ExamplePassword123!",
"Code": "123456",
"IsPasswordResetWithOTP": true
}
}Link-based password reset confirmation
Use this when the password reset flow was started from an email link. In this
case, Token should be included in the payload, the frontend should read the
token value from the password reset email link and send that token in the
request payload, and isOTP should be omitted or false.
await loginClient.confirmPasswordReset({
Email: "john.smith@example.com",
Password: "ExamplePassword123!",
Token: "token-from-email-link"
});Effective request body:
{
"Data": {
"Email": "john.smith@example.com",
"TenantID": "test-tenant",
"Password": "ExamplePassword123!",
"Token": "token-from-email-link"
}
}Authorization: Bearer eyJ_id_token_example may also be included when an ID token
is already stored.
API response
Status:
200
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}Refresh Token
Public signature: loginClient.refreshToken()
refreshToken() requires a previous successful login and a stored refresh token.
The client sends the stored refresh token and stores the returned token set in
memory.
await loginClient.refreshToken();Full API request
Request sent for the usage example above:
{
"Data": {
"RefreshToken": "eyJ_refresh_token_example",
"TenantID": "test-tenant"
}
}API response
Status:
200
{
"Data": {
"Email": null,
"RefreshToken": "eyJ_refresh_token_example",
"AccessToken": "eyJ_access_token_example",
"IDToken": "eyJ_id_token_example",
"EHR": null,
"ErrorMessage": null,
"HasInsurance": false,
"HasIDCard": false,
"HasSelfie": false,
"Attributes": null,
"ID": null,
"TenantID": "test-tenant",
"Expiration": "2030-01-01T00:00:00.000Z",
"Type": 0
},
"ErrorMessage": null,
"IsOK": true
}Get Auth Header
Public signature: loginClient.getAuthHeader()
Returns the authorization headers required for authenticated API requests. This method does not send an HTTP request, and other Healthcheck connectors can reuse the returned header object directly.
const headers = loginClient.getAuthHeader();Full API request
getAuthHeader() does not send an HTTP request.
The usage example above reads the value from local state.
API response
getAuthHeader() returns the current local header object.
{
"Authorization": "Bearer eyJ_id_token_example",
"X-Tenant-ID": "test-tenant"
}If an API key has been configured through setApiKey(...), the returned header object also includes the configured API key header.
Get Patient Header
Public signature: loginClient.getPatientHeader()
Calls the patient header endpoint and returns the raw server response. It requires a stored ID token.
const header = await loginClient.getPatientHeader();Full API request
getPatientHeader() does not send a request body.
API response
Status:
200
{
"Data": {
"Record": {
"Status": 1,
"Sex": "Male",
"GenderIdentity": "Male",
"HasInsurance": true,
"HasIDCard": true,
"HasSelfie": true,
"Flags": null,
"FirstName": "John",
"LastName": "Smith",
"MiddleName": null,
"BirthDate": "1990-01-01T00:00:00",
"Email": "john.smith@example.com",
"Phone": "+15555550123",
"Gender": "Male",
"Race": "White",
"Ethnicity": "",
"CRMID": null,
"AppleUserId": null,
"Address": {
"StreetAndNumber": "1 Main St",
"Extension": null,
"City": "Springfield",
"State": "IL",
"PostalCode": "62701",
"Country": "US"
},
"Attributes": {
"AthenaPatientID": "patient-id-example",
"AthenaGuarantorFirstName": "John",
"AthenaGuarantorLastName": "Smith",
"AthenaGuarantorEmail": "john.smith@example.com",
"AthenaCountryCode": "USA",
"AthenaDepartmentId": "1",
"AthenaEmailExists": "True",
"AthenaTestPatient": "False",
"PatientImageURL": "https://storage.example.com/selfie_example.jpg",
"CompositeID": "tenant-id/john.smith@example.com",
"Insurance": "EXAMPLE INSURANCE"
},
"CompositeID": "tenant-id/john.smith@example.com",
"FHIRID": "fhir-id-example",
"AthenaID": "patient-id-example",
"Created": "0001-01-01T00:00:00",
"Modified": "0001-01-01T00:00:00",
"CreatedByID": null,
"ModifiedByID": null,
"IsDeactivated": false,
"TenantID": "test-tenant",
"ID": "record-uuid-example"
},
"Encounters": null,
"EHR": "athena",
"PendingActions": [
"TAKE_TEST"
]
},
"ErrorMessage": null,
"IsOK": true
}Get Access Token
Public signature: loginClient.getAccessToken()
Returns the current in-memory access token.
const accessToken = loginClient.getAccessToken();Full API request
getAccessToken() does not send an HTTP request.
The usage example above reads the value from local state.
API response
getAccessToken() returns the current local access token value.
eyJ_access_token_example
Get ID Token
Public signature: loginClient.getIDToken()
Returns the current in-memory ID token.
const idToken = loginClient.getIDToken();Full API request
getIDToken() does not send an HTTP request.
The usage example above reads the value from local state.
API response
getIDToken() returns the current local ID token value.
eyJ_id_token_example
How It Works
- Create a shared
HttpClientinstance and a singleHCLoginClient. - Call
configure(...)once to store tenant and environment settings locally. - Call
register(...)if the patient account needs to be created. - Use
submitOnboardingStep(...)or the onboarding helper methods to complete required onboarding steps. - Call
login(...)to authenticate and store the returned access, refresh, and ID tokens in memory. - Use
refreshToken()to replace the current token set when a stored refresh token is available. - Use
getAuthHeader(),getAccessToken(),getIDToken(), andgetPatientHeader()for authenticated flows after login. - Other Healthcheck connectors can consume
getAuthHeader()instead of managing auth tokens directly.
Token Expiry and Refresh
The SDK does not auto-refresh tokens. Call refreshToken() proactively when the token is about to expire.
getTokens() returns the current in-memory token set, including expiresAt — an absolute Unix millisecond timestamp parsed from the Expiration field the backend returns.
isTokenExpired() is a helper that returns true when there is no stored token or when Date.now() >= expiresAt.
Recommended pattern:
async function ensureFreshToken(loginClient: HCLoginClient): Promise<void> {
if (loginClient.isTokenExpired()) {
await loginClient.refreshToken();
}
}
// Call before any authenticated connector operation
await ensureFreshToken(loginClient);
const result = await otherConnector.someMethod();getTokens() shape:
interface AuthTokens {
accessToken: string;
refreshToken: string;
idToken: string | null;
expiresAt: number; // absolute milliseconds since Unix epoch
}refreshToken() does not require a current ID token. It uses the stored refresh token from the previous successful login() call.
Notes
configure()stores tenant configuration locally and does not send an HTTP request.TenantIDis injected by the client into tenant-bound register, onboarding, login, refresh, and password requests.register(),verifyEmail(), andresendEmailVerify()all follow the same string-basedUser.Attributes.VERIFY_EMAIL_CODEpattern for OTP email verification flows.saveAddress()accepts anAddress.login()stores the initial token set internally, andrefreshToken()updates that stored token set when a refresh token is available.getPatientHeader()calls the patient header endpoint.getAuthHeader()returnsAuthorization: Bearer <idToken>+X-Tenant-ID. It does not carry an API key — each connector adds its own key independently.getAuthHeader(),getAccessToken(),getIDToken(),getBaseUrl(),getTenantId(),getTokens(), andisTokenExpired()return or evaluate local values and do not perform HTTP requests.- This connector is intended to be reused by other Healthcheck SDK connectors built on the same HTTP layer.
getPatientHeader vs getDashboard
HCLoginClient.getPatientHeader() calls /api/patient/header and returns a lightweight patient record plus pending actions. Typically called once after login to check patient state.
HCSettingsClient.getDashboard() (in hc-settings-connector) calls /api/patient/dashboard and returns a richer dashboard including encounters. These are different endpoints with different response shapes — not duplicates.