Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Mobile SSO

jay-lee00 edited this page May 1, 2019 · 4 revisions

Purpose

The Mobile SSO module is used to ensure that mobile apps can connect to the SnapMD system with the proper security and authentication protocols.

Mobile SSO diagram

The mobile application can be launched with the following URL: snapmdconnectedcare://?jwt=xxxxxxx

Process

Mobile SSO incorporates three different processes: SSO authentication, registration, and password reset capability.

The client must implement these capabilities as their own custom API endpoints, which extend the capabilities of the SnapMD system specifically for that client. The names and strutures of the endpoints do not need to follow a specific pattern or naming convention, but they do need to implement certain things in order to work with the SnapMD system properly. Those specific things are listed in the following sections.

All of the following endpoints must be public, and return publicly available HTTP statuses for both successful and erroneous execution.

SSO Authentication

In order to implement proper SSO authentication, a client must be able to do the following:

  1. Authenticate a user and generate a JWT (JSON Web Token) if authentication is successful.
  2. If the authentication is not successful, an error status should be returned.
  3. The JWT should be used to call the SnapMD Account Management and SSO API in order to retrieve an access token.
  4. If an access token cannot be retrieved, an error status should be returned.

The SSO authentication endpoint requires two critical fields, "Email" and "Password". "Email" is the user's email address, and "Password" is the user's password to get into the system.

The critical information needed to log into the SnapMD system is all of the following:

  1. The client's base URL
  2. The client hospital ID
  3. The API ID
  4. The API key

It is usually best to implement these pieces as part of a single object, but that is not required.

The SnapMD API function GetUserToken() should be used to retrieve a SnapMD system access token.

    //patientBearerToken 
    //response to be used by mobile
    public class SerializableToken
    {
        public string access_token { get; set; }

        public DateTimeOffset? expires { get; set; }
    }

Registration

In order to implement proper SSO registration, a client must be able to do the following:

  1. Register a user on the client system.
  2. If the client system registration is successful, it should use the Administrative Functions API to register a user in the SnapMD system.
  3. If the registration is not successful, an error status should be returned.

The following fields are required to be given to the endpoint for registering a user. These fields may be contained inside an object, but it is not essential for them to be.

  1. FirstName
  2. LastName
  3. Email
  4. Address
  5. Mobile Number With Country Code
  6. Gender
  7. Password

The SnapMD API function RegisterPatient() should be used to actually register the patient. Since this makes a significant change to the SnapMD system, administrative privileges in the SnapMD system are required to run this endpoint. This applies even though the implementation of the endpoint is specific to a client.

Once registration is complete, a user token is returned, similar to how the authentication endpoint (described above) works.

Password Reset

In order to implement password resets, a client must be able to do the following:

  1. Verify the user's request
  2. Send the user an email with which to reset their password

The SSO password reset endpoint requires one critical field, "Email", which is the user's email address. The implementation of this endpoint is completely client-specific; whatever is necessary for a particular client to be able to send a password reset email should be placed here. This can vary widely between clients.

Code Example

The following code goes through the process described above:

  1. Authenticates with the client back end (the app partner back end)
  2. Authenticates the admin user
  3. Retrieves the patient with the email of the logged in user
  4. If the user is not found, calls the API to create a new user
  5. Builds the JWT token for SSO
  6. Authenticates the patient with the JWT token

An implementation of the password reset functionality is not included here because it should be client-specific, as explained above.

private string adminUserName = "admin@myprovider.com";
private string adminPassword = "abc123!";
private string apiUrl = "https://myprovider.connectedcare.md/api/";
private int ourProviderId = 123;
private string apiKey = "123";
private string developerId = "abc";

private readonly ITokenApi _tokenApi = new TokenApi(apiUrl, ourProviderId, developerId, apiKey, new WebClientWrapper(new WebClient()));
private readonly IPatientAdminApi _patientAdminApi;

// Implementation of authentication method
public IAuthResponse Login(LoginModel model)
{

	// Authenticate the user with the client back end.
	// If authentication fails, return an error.
	var response = YourLoginImplementation.Authenticate(model.Email, model.Password);
	if (response.Status == ResponseStatus.Error)
	{
		return new AuthResponse(false, "User Name or Password is invalid.");
	}

	// Log in the admin user with SnapMD.
	// If the token isn't valid, return an error.
	var token = _tokenApi.GetToken(adminUserName, adminPassword, UserType.Clinician);
	if (string.IsNullOrWhiteSpace(token))
	{
		return new AuthResponse(false, "Error authenticating your user.");
	}

	// Use the patient admin API to retrieve the patient ID.
	// If the patient doesn't exist in the system, their record must be created first.
	_patientAdminApi = new PatientAdminApi(apiUrl, token, developerId, apiKey, new WebClientWrapper(new WebClient()));
	var patient = _patientAdminApi.GetPatient(model.Email);
	var patientId = 0;
	if (patient == null)
	{
		var record = YourPatientProfileRepository.GetPatient(model.Email);
		patientId = _patientAdminApi.AddPatient(new PatientOnBoardShortDetail
		{
			// The patient's record data should be placed here.
		});
	}
	else
	{
		patientId = patient.PatientId;
	}

	// Create the SSO token (JWT).
	var jwtToken = BuildToken(patientName, model.Email, "patient");

	// Get an authentication bearer token from SnapMD.
	var patientBearerToken = _tokenApi.GetToken(jwtToken);

	// If an error occurred obtaining the authentication bearer token, return the error.
	if (patientBearerToken == null)
	{
		return new AuthResponse(false, "Eror authenticating your user.");
	}

	// Store the token and use it on all the API calls in this session.
	return AuthResponse(true, "success", patientBearerToken);
}

// Implementation of registration method
public IAuthResponse Register(RegistrationModel model)
{

	// Make sure your registration credits are valid.
	var response = YourRegistrationImplementation.Register(model);
	if (response.Status == ResponseStatus.Error) {
		return new AuthResponse(false, "User Name or Password is invalid.");
	}

	// Use the patient admin API to retrieve the patient ID.
	// If the patient doesn't exist in the system, their record must be created first.
	_patientAdminApi = new PatientAdminApi(apiUrl, token, developerId, apiKey, new WebClientWrapper(new WebClient()));
	var patient = _patientAdminApi.GetPatient(model.Email);
	var patientId = 0;
	if (patient == null)
	{
		patientId = _patientAdminApi.AddPatient(new PatientOnBoardShortDetail
		{
			// The patient's registration data should be placed here.
		});
	}
	else
	{
		patientId = patient.PatientId;
	}

	// Create the SSO token (JWT).
	var jwtToken = BuildToken(patientName, model.Email, "patient");

	// Get an authentication bearer token from SnapMD.
	var patientBearerToken = _tokenApi.GetToken(jwtToken);

	// If an error occurred obtaining the authentication bearer token, return the error.
	if (patientBearerToken == null)
	{
		return new AuthResponse(false, "Eror authenticating your user.");
	}

	// Store the token and use it on all the API calls in this session.
	return AuthResponse(true, "success", patientBearerToken);
}

Clone this wiki locally