Skip to content

Introduction

The application authentication process is designed to secure both parties(Vim and application) by safeguarding access to resources and preventing unauthorized injections. This process focuses on three key objectives:

  1. Secured access to EHR resources:

Ensure that access to Electronic Health Records (EHR) resources exposed by Vim is secure and compliant with industry standards.

  1. Third-Party authentication via SSO:

Enhance user experience by enabling Single Sign-On (SSO) with Vim acting as the Identity Provider (IDP), facilitating seamless third-party authentication.

  1. Delegate SDK authorization to the application:

Empower the application to determine whether the user is authorized to utilize the VimOS SDK and to halt SDK initialization if they are not. This enables the app to seamlessly onboard and offboard users without requiring extra integration.

OAuth 2.0 in Vim

Vim OS Apps initialization process is based upon OAuth 2.0, an authorization framework protocol that allows a third-party website or application access to the user's protected resources.

An OAuth 2.0 flow has the following roles:

  • Resource owner: Entity that can grant access to a protected resource. In this case, the clinic.
  • Resource server: Server hosting the protected resources. This is the API you want to access. In this case, Vim OS.
  • Client: Application requesting access to a protected resource. This is your App.
  • Authorization server: Server that authenticates the Resource Owner and issues access tokens after proper authorization. In this case, Vim.

OpenId Connect

VimOs implements OpenID Connect (OIDC) on top of OAuth2 to enable seamless Single Sign-On (SSO) with third-party applications.

OpenID Connect (OIDC) is an identity layer on top of the OAuth 2.0 protocol, which allows clients to verify the identity of the end-user based on the authentication performed by an authorization server, as well as to obtain basic profile information about the end-user in an interoperable and REST-like manner. Essentially, it provides the third-party app with Single Sign-On (SSO).

Key Features

  • ID Token: A JWT (JSON Web Token) that contains user identity information, issued by the authorization server.

  • UserInfo Endpoint: An endpoint that returns additional claims about the authenticated user.

OAuth 2.0 endpoints

OAuth 2.0 consists three main endpoints:

Authorization endpoint

http
GET https://connect.getvim.com/os-api/v1/oauth/authorize?launch_id={{vimLaunchId}}&client_id={{yourClientId}}&redirect_uri={{yourAppUrl}}

The endpoint is used to interact with the resource owner and get authorization to access the protected resource.

  • Request parameters
ParameterDescription
client_idClient ID connected to your account.
redirect_uriA successful response from the Authorization endpoint results in a redirect to this URL.
The URL must match the base URL from your application manifest.
launch_idVim OS Application launch_id.
This is provided automatically by the VimOS
  • Redirect response
http
HTTP/1.1 302 Found
Location: {yourAppUrl}?code=AUTHORIZATION_CODE

The endpoint will issue an authorization code and will pass it as part of the query params to the redirect_uri. This code will later be exchanged for access token & id tokens using the token endpoint.

ParameterDescription
codeA one-time use query parameter used for secure authorization in the authentication flow.

Token endpoint

http
POST https://connect.getvim.com/os-api/v1/oauth/token
Content-Type: application/json

The application uses the endpoint to obtain an access token and id token. The application provides the authorization code received from the authorization endpoint in exchange for the tokens.

  • Request body
FieldDescription
client_idClient ID connected to your account.
codeThe authorization code from the authorization endpoint.
secretSecret connected to your account.
  • Response payload
fieldDescription
accessTokenJWT token to be presented to vim when calling SDK to fetch EHR resource.
idTokenJWT token with the authenticated user information. Follows standard OIDC format. and is issued exclusively to the application.

Id token example:

json
{
  "iss": "https://auth.getvim.com",
  "sub": "auth0|550e8400-e29b-41d4-a716-446655440000",
  "aud": "{{yourClientId}}",
  "exp": 1311281970,
  "iat": 1311280970,
  "given_name": "Jane",
  "family_name": "Doe",
  "email": "[email protected]"
}

UserInfo endpoint

http
GET https://connect.getvim.com/os-api/v1/oauth/userinfo
Authorization: '{ACCESS_TOKEN}'

An application can use the endpoint to fetch additional info on the authenticated user. The application provides the access token it received from the token endpoint as authorization header and will receive payload with the user details.

required permissions

WARNING

Your application will only receive data for fields with explicitly declared read access in the Developer Console. Fields of the user entity without declared read access will consistently return undefined. Permissions for fields are grouped into dedicated subsections, allowing you to grant or revoke access to related groups of fields as needed.

user permissions read

  • Request headers
HeaderDescription
AuthorizationThe standard header populated with access token received from Vim.
  • Response payload
FieldDescription
emailAuthenticated user email, unique identifier in Vim, can be used by the app for identification.
subUnique identifier of the authenticated user in Vim, can be used by the app for identification.
family_nameAuthenticated user last name, Optional.
given_nameAuthenticated user first name, Optional.
https://getvim.com/ehrUsernameEHR username.
https://getvim.com/organizationVim organization. Represents the clinic entity. A JSON object with the following fields: id(Vim identifier) and name.

Response example:

json

{
    "email": "[email protected]",
    "sub": "auth0|550e8400-e29b-41d4-a716-446655440000",
    "family_name": "Doe",
    "given_name": "Jane",
    "https://getvim.com/ehrUsername": "janedoe",
    "https://getvim.com/organization": {
        "id": "12345",
        "name": "Jane Doe Organization"
    }
}

The initialization sequence explained

  1. Pre condition: the user authenticates to Vim and Vim OS loads.
  2. Launch endpoint: When Vim OS starts the app loading process it first calls the app launch endpoint URL, provided in the Developer Console. With the correct request parameters in place, the launch endpoint must redirect to Vim's authorization endpoint.
  3. Authorization Server: Vim’s authorize endpoint will issue an authorization code and redirect to the provided verified redirect_uri, which should be the App’s main page, with the authorization code as a query param in the url.
  4. App initialization: Your App code is loaded and should initialize a VimOS instance. See examples below.
    1. The SDK uses the authorization code from the URL query param and calls your app backend token endpoint (a URL provided in the initialize method) with the authorization code.
    2. Your App backend should call the Vim OS token endpoint with the authorization code & the app's secret and client ID.
    3. The Vim OS token endpoint returns an access token and an id token to your app backend.
    4. Your app backend identifies and authorizes the user based on the id token and/or userProfile endpoints.
    5. The app backend returns both the access token and id token to the SDK.
  5. Secure communication: After Vim OS verifies the access token, a secure communication channel is established and maintained between VimOS and the Application.
  6. Optional step - application SSO: Utilize generated id token to authenticate the user on application end.
    1. The SDK then resolves the init process with the application id token which was generated exclusively to it.
    2. The application can now use the id token to generate its own access token for use when calling its internal APIs.
mermaid diagram sso

Implementation step by step guide

You will need to have a running app backend server, and pass the correct parameters when initializing the VimOS SDK.

Important!

TIP

To test your application, first integrate the SDK into your codebase. Next, implement the application authentication flow. Develop and test this flow in the Vim Sandbox EHR, as communication between Vim and your application requires your application to run in the Vim Hub on an EHR. When Vim injects your application iframe in the Sandbox EHR, VimOS automatically sends a request to your launch token url defined in the manifest with the launch_id.

App backend server

Your server will need to handle 2 incoming requests:

1. The launch endpoint

The launch endpoint will be called by VimOS frontend in order to issue an authorization code via Vim’s authorize endpoint.

Your launch endpoint url will:

  • Receive an incoming GET request with a launch_id and vim_organization_id as a query parameters.
  • Redirect the call to https://connect.getvim.com/os-api/v1/oauth/authorize with 3 query parameters described above: launch_id, client_id, redirect_uri.
  • vim_organization_id - A unique identifier for the clinic in Vim where the app is rendered. The launch endpoint can use this parameter to perform logic when constructing the final redirect_uri (optional step for multi-tenant apps).

2. The app token endpoint

The app token endpoint will be called by the VimOS SDK in order to exchange the authorization code with an access token via Vim’s authorize endpoint. it is responsible also for adding additional layer of application authorization.

Your app token endpoint will:

  • Receive an incoming POST request with the code in the JSON body.
  • Send a POST request to https://connect.getvim.com/os-api/v1/oauth/token with the code, client_id and secret in the request JSON body.
  • Receive a JSON response with the access token and id token.
  • Authorize user: verify id token and check the user identity against the application database to confirm their authorization status. See id token verification section for more details.
  • Respond appropriately:
    • If the user is successfully authorized, return the token endpoint JSON response to the incoming request.
    • If the user is not authorized, return a 403 Forbidden status code.

CORS support

TIP

Since the Vim-OS SDK operates from a different domain than your application, it is essential to configure your backend to support Cross-Origin Resource Sharing (CORS) for the getvim.com domain.

To ensure smooth operation and avoid potential issues with token handling and launch requests, we recommend using standard CORS libraries. These libraries provide a reliable solution for managing cross-origin requests and help prevent common problems associated with CORS. Otherwise, you may face issues such as incorrect handling of preflight OPTIONS requests.

Example:

js
import express from 'express';
import fetch from 'node-fetch';
import cors from 'cors';

const app = express();

// Allow incoming requests from the Vim SDK
app.use(
  cors({
    origin: [/\.getvim\.com$/],
  }),
);

// It's recommended to store your account's client id and secret in environment variables
// You can find the values in your Vim account page: https://console.getvim.com/organization-admin/my-account
const clientId = process.env.CLIENT_ID;
const secret = process.env.CLIENT_SECRET;

// Replace with the actual base URL from your application manifest
const redirectUri = 'https://application-domain.com/main-app';

app.use(express.json());
app.get('/api/launch-app', (req, res) => {
  const launchId = req.query.launch_id;

  // Build the authorization URL to redirect to
  const authorizationUrl = new URL('https://connect.getvim.com/os-api/v1/oauth/authorize');
  authorizationUrl.searchParams.set('launch_id', launchId);
  authorizationUrl.searchParams.set('client_id', clientId);
  authorizationUrl.searchParams.set('redirect_uri', redirectUri);

  // Redirect the request
  res.redirect(authorizationUrl.toString());
});

app.post('/api/generate-token', async (req, res) => {
  const { code } = req.body;

  const vimResponse = await fetch('https://connect.getvim.com/os-api/v1/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ client_id: clientId, code, secret }),
  });

  if (!(await isAuthorized(vimResponse))) {
    return res.status(403).send('Forbidden: You do not have access to this resource.');
  }

  const tokenData = await vimResponse.json();
  res.json(tokenData);
});
app.listen(3000, () => console.log('Server listening on port 3000'));

async function isAuthorized(vimResponse) {
  // Validate ID token, call userinfo endpoint if needed, and apply custom logic to check against your application's database.
  // Refer to the Id token verification section for an example.
}

Id token verification

When you need to identify a user and determine their access to your application, verifying the JWT ID token is crucial. Follow these guidelines to ensure proper verification:

  1. Library: Utilize any third-party JWT library for token verification.

  2. Algorithm: The JWT ID token uses the RS256 algorithm.

  3. JWKS URI: The JSON Web Key Set (JWKS) can be retrieved from the following URI: https://auth.getvim.com/.well-known/jwks.json.

  4. Issuer: Verify that the token’s issuer (iss) matches the following URL: https://auth.getvim.com/.

  5. Audience: Ensure that the aud (audience) field in the ID token matches the client ID of your application.

By adhering to these steps, you can accurately verify the JWT ID token and ensure its validity.

Example:

js
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const jwtClient = jwksClient({
  jwksUri: 'https://auth.getvim.com/.well-known/jwks.json',
});

const clientId = process.env.CLIENT_ID;

async function verifyToken(idToken) {
  const options = {
    audience: clientId,
    issuer: 'https://auth.getvim.com/',
    algorithms: ['RS256'],
  };

  return new Promise((resolve, reject) => {
    jwt.verify(idToken, getKey, options, (err, decoded) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(decoded);
    });
  });
}

function getKey(header, callback) {
  jwtClient.getSigningKey(header.kid, function (err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

Initializing the VimOS SDK from your app

ts
const vimOS = await window.vimSdk.initializeVimSDK();
// Use VimOS instance for further interactions with VimOS.js
ts
import { loadSdk } from 'vim-os-js-browser';

async function init() {
  const vimOS = await loadSdk();
  // Use vimOS instance for further interactions with VimOS.js
}
init();

tip

TIP

Once the SDK initialization and authentication process is complete, your application's default activation status is Disabled. This means it will appear grayed out on the Vim Hub, without an option for users to click and open the iframe. If you wish to make your application accessible, you must proactively change the activation status to Enabled.

However, we advise enabling your application only when there is tangible value for end-users to access it, to prevent user fatigue from encountering your app without immediate action or value. You can dynamically control the activation status following these instructions.

Optional - application SSO

To enable Single Sign-On (SSO) in your application, follow these steps:

  1. Initialize the SDK: Start by initializing the SDK with initializeVimSDK(). This method sets up the SDK and provides you with a vimOs object.

  2. Retrieve the ID Token: Once the SDK is initialized, use the vimOs.sessionContext.getIdToken() method to obtain the OIDC ID token JWT. This token is generated specifically for your application and serves as proof of authentication.

  3. Generate Internal Access Token: With the ID token in hand, your application can create its own internal access token. The method for generating this internal access token is entirely up to your application’s authentication implementation. The vim-os SDK does not influence or control how this access token is created or managed. This internal access token is used for managing user sessions and securely accessing resources within your application.

By leveraging this SSO flow, your application can provide a smoother and more seamless user experience, reducing the need for repeated logins and improving overall access management.

Example:

ts
const vimOs = await window.vimSdk.initializeVimSDK();

const { idToken } = await vimOs.sessionContext.getIdToken();

const yourOwnAccessToken = await exchangeIdTokenForAccessToken(idToken);

// Use access token to call your own backend...


async function exchangeIdTokenForAccessToken(idToken) {
  const response = await fetch('https://your-auth-server.com/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ idToken }),
  });

  const data = await response.json();
  return data.accessToken;
}
ts
import { loadSdk } from 'vim-os-js-browser';

async function init() {
  const vimOs = await loadSdk();

  const { idToken } = await vimOs.sessionContext.getIdToken();

  const yourOwnAccessToken = await exchangeIdTokenForAccessToken(idToken);

  // Use access token to call your own backend...
}

async function exchangeIdTokenForAccessToken(idToken) {
  const response = await fetch('https://your-auth-server.com/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ idToken }),
  });

  const data = await response.json();
  return data.accessToken;
}

init();

Testing the authentication flow

To help you with testing the authentication flow in a local development environment.
We have created a Postman collection that you can use to test the authentication flow.

Setup

Steps to test the authentication flow

  1. Extract the access token from the sandbox EHR
    • Open the sandbox EHR
    • Go to the Vim Settings page
    • Copy the access token
Mock EHR settings page
  1. Set up the environment variables in Postman
    • authToken: The access token from the vim settings page in the sandbox EHR
      • Note: The access token is only valid for 30 minutes; If you start receiving an Authentication failed response from the Create App Launch ID request, reload the sandbox EHR and extract a new token
    • appId: Your app ID
    • appVersion: Your app version
    • clientId: The client ID from your account page
    • clientSecret: The client Secret from your account page
    • launchEndpoint: Your backend launch endpoint
    • appTokenEndpoint: Your backend token endpoint

Be sure to save (ctrl+s) your changes to the variables; Postman doesn't auto save them.

You are not required to set the other variables, they will be auto populated by the collection logic.

Postman variables
  1. Start running the API calls in the collection.
    When you run each request, some verifications are ran afterwards to verify the response is correct.
    The collection also stores results in variables that are being used by the following API calls, so you should run them in the following order.
    • Create App Launch ID - Calls Vim backend to generate the launch ID and store it as a collection variable
    • Launch - Calls your backend launch endpoint with the launch ID, The collection will verify the response and store the authorization code as a collection variable
    • Vim OS Authorize Endpoint - Calls Vim backend to verify the authorization request, The response should be a redirect request to your application with the authorization code as a query parameter.
    • App Token Endpoint - Calls your backend token endpoint with the authorization code, The response should contain access token and id token.
    • UserInfo Endpoint - Calls Vim backend with the access token, The response should contain the authenticated user information.

In case of errors, the collection will provide you with detailed error messages.