Appearance
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:
- Secured access to EHR resources:
Ensure that access to Electronic Health Records (EHR) resources exposed by Vim is secure and compliant with industry standards.
- 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.
- 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
Parameter | Description |
---|---|
client_id | Client ID connected to your account. |
redirect_uri | A 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_id | Vim 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.
Parameter | Description |
---|---|
code | A 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
Field | Description |
---|---|
client_id | Client ID connected to your account. |
code | The authorization code from the authorization endpoint. |
secret | Secret connected to your account. |
- Response payload
field | Description |
---|---|
accessToken | JWT token to be presented to vim when calling SDK to fetch EHR resource. |
idToken | JWT 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.
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.
- Request headers
Header | Description |
---|---|
Authorization | The standard header populated with access token received from Vim. |
- Response payload
Field | Description |
---|---|
Authenticated user email, unique identifier in Vim, can be used by the app for identification. | |
sub | Unique identifier of the authenticated user in Vim, can be used by the app for identification. |
family_name | Authenticated user last name, Optional. |
given_name | Authenticated user first name, Optional. |
https://getvim.com/ehrUsername | EHR username. |
https://getvim.com/organization | Vim 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
- Pre condition: the user authenticates to Vim and Vim OS loads.
- 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.
- 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. - App initialization: Your App code is loaded and should initialize a
VimOS
instance. See examples below.- 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.
- Your App backend should call the Vim OS token endpoint with the authorization code & the app's secret and client ID.
- The Vim OS token endpoint returns an access token and an id token to your app backend.
- Your app backend identifies and authorizes the user based on the id token and/or userProfile endpoints.
- The app backend returns both the access token and id token to the SDK.
- Secure communication: After Vim OS verifies the access token, a secure communication channel is established and maintained between VimOS and the Application.
- Optional step - application SSO: Utilize generated id token to authenticate the user on application end.
- The SDK then resolves the init process with the application id token which was generated exclusively to it.
- The application can now use the id token to generate its own access token for use when calling its internal APIs.
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 alaunch_id
andvim_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 finalredirect_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 thecode
in the JSON body. - Send a
POST
request tohttps://connect.getvim.com/os-api/v1/oauth/token
with thecode
,client_id
andsecret
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:
Library: Utilize any third-party JWT library for token verification.
Algorithm: The JWT ID token uses the RS256 algorithm.
JWKS URI: The JSON Web Key Set (JWKS) can be retrieved from the following URI: https://auth.getvim.com/.well-known/jwks.json.
Issuer: Verify that the token’s issuer (
iss
) matches the following URL:https://auth.getvim.com/
.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:
Initialize the SDK: Start by initializing the SDK with initializeVimSDK(). This method sets up the SDK and provides you with a vimOs object.
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.
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
- Have an app configured in Console
- Install Postman
- Import the Postman collection
- Configure postman to not follow redirects
- Go to Settings -> General -> Headers -> Automatically follow redirects -> Turn it off
- Go to Settings -> General -> Headers -> Automatically follow redirects -> Turn it off
Steps to test the authentication flow
- Extract the access token from the sandbox EHR
- Open the sandbox EHR
- Go to the Vim Settings page
- Copy the access token
- 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 theCreate App Launch ID
request, reload the sandbox EHR and extract a new token
- Note: The access token is only valid for 30 minutes; If you start receiving an
appId
: Your app IDappVersion
: Your app versionclientId
: The client ID from your account pageclientSecret
: The client Secret from your account pagelaunchEndpoint
: Your backend launch endpointappTokenEndpoint
: 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.
- 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 variableLaunch
- Calls your backend launch endpoint with the launch ID, The collection will verify the response and store the authorization code as a collection variableVim 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.