Skip to main content
Glama
getwsbindingtoken.ts5.76 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { allOk, badRequest, normalizeErrorString, resolveId } from '@medplum/core'; import type { FhirRequest, FhirResponse } from '@medplum/fhir-router'; import type { OperationDefinition, Subscription } from '@medplum/fhirtypes'; import { getConfig } from '../../config/loader'; import { getAuthenticatedContext } from '../../context'; import { generateAccessToken } from '../../oauth/keys'; import { buildOutputParameters } from './utils/parameters'; const ONE_HOUR = 60 * 60 * 1000; export type AdditionalWsBindingClaims = { subscription_id: string; }; // Source (for backport version): https://build.fhir.org/ig/HL7/fhir-subscription-backport-ig/OperationDefinition-backport-subscription-get-ws-binding-token.json.html // R5 definition: https://build.fhir.org/operation-subscription-get-ws-binding-token.json.html const operation: OperationDefinition = { resourceType: 'OperationDefinition', id: 'backport-subscription-get-ws-binding-token', extension: [ { url: 'http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm', valueInteger: 0, }, { url: 'http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status', valueCode: 'trial-use', }, { url: 'http://hl7.org/fhir/StructureDefinition/structuredefinition-wg', valueCode: 'fhir', }, ], url: 'http://hl7.org/fhir/uv/subscriptions-backport/OperationDefinition/backport-subscription-get-ws-binding-token', version: '1.2.0-ballot', name: 'R5SubscriptionGetWsBindingToken', title: 'Get WS Binding Token for Subscription Operation', status: 'active', kind: 'operation', date: '2020-11-30', publisher: 'HL7 International / FHIR Infrastructure', contact: [ { name: 'HL7 International / FHIR Infrastructure', telecom: [ { system: 'url', value: 'http://www.hl7.org/Special/committees/fiwg', }, ], }, { name: 'Gino Canessa', telecom: [ { system: 'email', value: 'mailto:gino.canessa@microsoft.com', }, ], }, ], description: 'This operation is used to get a token for a websocket client to use in order to bind to one or more subscriptions.', jurisdiction: [ { coding: [ { system: 'http://unstats.un.org/unsd/methods/m49/m49.htm', code: '001', display: 'World', }, ], }, ], affectsState: false, code: 'get-ws-binding-token', resource: ['Subscription'], system: false, type: true, instance: true, parameter: [ { name: 'id', use: 'in', min: 0, max: '*', documentation: 'At the Instance level, this parameter is ignored. At the Resource level, one or more parameters containing a FHIR id for a Subscription to get a token for. In the absense of any specified ids, the server may either return a token for all Subscriptions available to the caller with a channel-type of websocket or fail the request.', type: 'id', }, { name: 'token', use: 'out', min: 1, max: '1', documentation: 'An access token that a client may use to show authorization during a websocket connection.', type: 'string', }, { name: 'expiration', use: 'out', min: 1, max: '1', documentation: 'The date and time this token is valid until.', type: 'dateTime', }, { name: 'subscription', use: 'out', min: 0, max: '*', documentation: 'The subscriptions this token is valid for.', type: 'string', }, { name: 'websocket-url', use: 'out', min: 1, max: '1', documentation: 'The URL the client should use to connect to Websockets.', type: 'url', }, ], }; /** * Handles a GetWsBindingToken request. * * Endpoint - Binding Token for WebSocket Subscription connection. * * URL: [base]/Subscription/$get-ws-binding-token * * URL: [base]/Subscription/[id]/$get-ws-binding-token * * See: https://build.fhir.org/subscription-operation-get-ws-binding-token.html * @param req - The FHIR request. * @returns The FHIR response. */ export async function getWsBindingTokenHandler(req: FhirRequest): Promise<FhirResponse> { const { login, profile, repo, project } = getAuthenticatedContext(); const { baseUrl } = getConfig(); if (!project.features?.includes('websocket-subscriptions')) { return [badRequest('WebSocket subscriptions not enabled for current project')]; } const clientId = login.client && resolveId(login.client); const userId = resolveId(login.user); if (!userId) { return [badRequest('Login missing user')]; } const { id: subscriptionId } = req.params; try { await repo.readResource<Subscription>('Subscription', subscriptionId); } catch (err: unknown) { return [badRequest(`Error reading subscription: ${normalizeErrorString(err)}`)]; } const token = await generateAccessToken( { client_id: clientId, login_id: login.id as string, sub: userId, username: userId, scope: login.scope as string, profile: profile.reference as string, }, { additionalClaims: { subscription_id: subscriptionId, } satisfies AdditionalWsBindingClaims, } ); const output = { token, expiration: new Date(Date.now() + ONE_HOUR).toISOString(), subscription: subscriptionId, 'websocket-url': `${baseUrl.replace('http://', 'ws://').replace('https://', 'wss://')}ws/subscriptions-r4`, }; return [allOk, buildOutputParameters(operation, output)]; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server