ExorLive Authentication - OAuth 2.0

ExorLive uses OAUTH 2.0 for authentication.

It is important that you have been in contact with support and have all your credentials in order before you try to make any API calls.

See the code samples for a description of how this may be implemented in a partner application.

There are two main ways to authenticate:

  1. With a username and password or OpenID.
    This gives access to an API that allows to do anything that may be done in the ExorLive Web Application.
    In fact ExorLive itself uses this API.
    How to use this is not the scope of this documentation. Contact us if you want to know more about this.
  2. With an application-key and application-secret.
    This gives access to a different API with limited functionality, but enough functionality to do what many of our link-partners may require.
    This API is the scope here, and is used in the code samples.

    The OAuth parameter called "redirect_uri" will in our case NOT be used for redirecting, only for authentication. Use the value for RequesterUrl that you receive together with ClientKey and ClientSecret. The three parameters ClientKey, ClientSecret and RequesterUrl are together used to validate the AccessToken request. All three parameters must match exactly as received from ExorLive Support.

    The code snippets are written in C# / .NET, but the principles here may be implemented in any language that supports HTTP and JSON strings.
    							
    AuthDomain = "https://auth.exorlive.com";
    AppDomain = "https://exorlive.com";
    
    // Suggested scope for this sample
    _scope = "read_profile read_workout read_master read_calendar read_contact create_session configure";
    
    /*
    	This function can be used to authorize both an admin user and a normal user created by an admin.
    	Just make sure to use the matching userId.
    */
    public async Task<string> GetAccessToken(int userId)
    {
    	string url = AuthDomain + "/Providers/OAuth/Authorize.aspx";
    	try
    	{
    		HttpClient httpClient = new HttpClient();
    
    		// This is used to make it easier to look up the calls in our logs.
    		string clientName = "<The name of your application>"; 
    
    		// This uses OAuth 2.0 conventions.
    		//
    		// Step 1: Get the Auth Code.
    		//
    		url += "?user_id=" + userId;         // user_id === admin id or contact id
    		url += "&response_type=code";        // this is an OAuth2 standard
    		url += "&client_id=" + ClientKey;    // given by ExorLive support
    		url += "&client_secret=" + ClientSecret;   // given by ExorLive support
    		url += "&redirect_uri=" + HttpUtility.UrlEncode(RequesterUrl);   // given by ExorLive support
    		url += "&scope=" + _scope;
    
    		var request1 = new HttpRequestMessage(HttpMethod.Get, url);
    		request1.Headers.Add("ExorLive-Client", clientName);
    		HttpResponseMessage response1 = await httpClient.SendAsync(request1);
    		if (!response1.IsSuccessStatusCode)
    		{
    			string errormessage = $"GetAccessToken({userId}) STEP1: {response1.StatusCode} {response1.ReasonPhrase} {await response1.Content.ReadAsStringAsync()}";
    			_logger.LogError(errormessage);
    			return null;
    		}
    		string json1 = await response1.Content.ReadAsStringAsync();
    		dynamic codeResponseAsDynamic = JsonConvert.DeserializeObject<dynamic>(json1);
    		string code = codeResponseAsDynamic.code;
    
    
    		//
    		// Step 2: Given the Auth Code, get the AccessToken.
    		//
    		url = AuthDomain + "/Providers/OAuth/Token.ashx";
    		string data = "grant_type=authorization_code";
    		data += "&client_id=" + ClientKey;
    		data += "&client_secret=" + ClientSecret;
    		data += "&code=" + code;
    		data += "&redirect_uri=" + HttpUtility.UrlEncode(RequesterUrl);
    
    		var request2 = new HttpRequestMessage(HttpMethod.Post, url);
    		request2.Headers.Add("ExorLive-Client", clientName);
    		request2.Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
    		HttpResponseMessage response2 = await httpClient.SendAsync(request2);
    		if (!response2.IsSuccessStatusCode)
    		{
    			string errormessage = $"GetAccessToken({userId}) STEP2: {response2.StatusCode} {response2.ReasonPhrase} {await response2.Content.ReadAsStringAsync()}";
    			_logger.LogError(errormessage);
    			return null;
    		}
    		string json2 = await response2.Content.ReadAsStringAsync();
    		dynamic tokenResponseAsDynamic = JsonConvert.DeserializeObject<dynamic>(json2);
    
    		// The refresh_token and expires_in can be ignored if you only use short lived accesstokens.
    		string RefreshToken = tokenResponseAsDynamic.refresh_token;
    		DateTime TokenExpiration = DateTime.UtcNow.AddSeconds(tokenResponseAsDynamic.expires_in);
    
    		string accessToken = tokenResponseAsDynamic.access_token;
    		return accessToken;
    	}
    	catch (Exception ex)
    	{
    		if (ex.Message.Contains("No connection"))
    		{
    			string errormessage = $"GetAccessToken: Failed to connect to the server: {new Uri(url).Host}: {ex.Message}";
    			_logger.LogError(errormessage);
    		}
    		else
    		{
    			string errormessage = $"GetAccessToken({userId}) EXCEPTION: {ex.Message}";
    			_logger.LogError(errormessage);
    		}
    		return null;
    	}
    }
    				
    				

    The JSON response with the token might look like this:

    					
    {
        "access_token": "AAEAAByQvXG9ToTIGqv...55Jvw",
        "token_type": "bearer",
        "expires_in": "7200",
        "refresh_token": "fYz1!IAAAAPU6P...FA0QLteA",
        "scope": "read_profile read_workout create_session"
    }
    						
    

    The access-token that you get is valid for 2 hours. You may just ask for a new token each time you need one or you may track its expiration and get a new one then, either from scratch or using the refresh-token. The exact time of the expiration of the token is found in the property tokenresponse.expires_in.

    An expired token may be refreshed this way:

    	
    private string RefreshToken { get; set; }
    private DateTime TokenExpiration { get; set; }
    private string RefreshAccessToken()
    {
    	if ((!string.IsNullOrWhiteSpace(RefreshToken)) && TokenExpiration < DateTime.UtcNow)
    	{
    		string postData = String.Format("grant_type=refresh_token&client_id={0}&client_secret={1}&refresh_token={2}&redirect_uri={3}",
    			ClientKey,
    			ClientSecret,
    			RefreshToken,
    			HttpUtility.UrlEncode(_requesterDomain)
    		);
    		var tokenUrl = String.Format("{0}/Providers/OAuth/Token.ashx", Authdomain);
    		var response = WebMsg(tokenUrl, "POST", data, "application/x-www-form-urlencoded", null);
    		try
    		{
    			// Deserialize the JSON to a dynamic object
    			var tokenresponse = JsonConvert.DeserializeObject<dynamic>(response);
    
    			// Get the vital information form the JSON response.
    			RefreshToken = tokenresponse.refresh_token;
    			TokenExpiration = DateTime.UtcNow.AddSeconds(tokenresponse.expires_in);
    
    			// Return the token
    			return tokenresponse.access_token;
    		}
    		catch (ArgumentException)
    		{
    			// This will happen when there is invalid token data.
    			RefreshToken = null;
    			return null;
    		}
    	}			
    }
    
    
    

    For all the details, see the downloadable codesamples.