Integration using OAuth 2.0
Developer documentation for secure integration with Huddle APIs
Standard protocol
Huddle uses the OAuth 2.0 protocol (proposed) for authorisation of requests to our public APIs. OAuth is a mature standard which is widely discussed and implemented. The protocol specification can be retrieved at: http://oauth.net/documentation/spec/. This page represents an abbreviated summary of the spec as implemented by Huddle. Unless otherwise indicated on this page, our implementation conforms to the standard specification.
Huddle's implementation
Technical details, including the authorization endpoint URI can be found in the
service documentation located at:
http://login.huddle.net/docs/servicedescription
A summary of the basic protocol parameters features is as follows:
Feature | Support |
Client profiles | Huddle actively supports both "Web Server" and "User-Agent" client profiles. |
Access Grant expiration | By default, Access Grants expire after one year. This may be varied by client or application. |
Token expiration | The standard token expiration period is twenty minutes. |
Process summary
1.Registering your client
How to identify your application to Huddle's authorization server
Before accessing Huddle APIs, you need to register your application.
Please supply the following information to api@huddle.com:
- Application name
- Company (if appropriate)
- Contact name, phone and address
- Contact email
- Redirect URI (see discussion below, or OAuth Spec., Section 3, “redirect_uri”)
- Is this a web application, a desktop application, or an application running on a device?
- Short description of your application
You should receive a confirmation of receipt of your request within one business day. We aim to process all requests within three business days.
2.Obtaining End-User Authorisation
How to request authorisation to access a user's data through Huddle's APIs
When a user first uses your application, you will need to request authorisation to access Huddle data on their behalf. This process requires the user to authenticate with Huddle's authorisation server, and to agree to authorise access to their data from your application. Once this process is complete, the authorisation server will redirect the user back to your registered Redirect URI, including an Authoization Code.
Reference: OAuth 2.0 Specification, Sections: 3 , 3.1
- Initial Request
-
Your code should issue a request to the authorize endpoint of Huddle's Authorisation Server, as shown below:
GET /request?response_type=code&client_id=s6BhdRkqt&redirect_uri=MyAppUri%3A%2F%2FMyAppServer.com/receiveAuthCode HTTP/1.1
Host: login.huddle.netThe querystring values should be replaced with values specific to your application, with the exception of the
response_type
value:Key Value response_type Should be code
. Other values are not supported.client_id This should be your registered Client ID redirect_uri This should be your registered Redirect URI 1
1 If you are developing a web application, this URI will probably use the https:// scheme. However, custom schemes are also supported in order to enable other types of applications.
- Typical response
-
The initial response to this request will be an authentication and authorisation screen which the end-user must complete.
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
. . .
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html id="api" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Log in to authorise this request<title>
</head>
<body>
. . .
<form action="https://login.huddle.net/authoriseGrantRequest" method="POST">
. . .
</form>
</body>
</html>
If the user successfully authorises the request, the server will redirect the user back to your registered Redirect URI, including the Authorisation Code
HTTP/1.1 302 Found
Location: MyAppUri://MyAppServer.com/receiveAuthCode?code=ilWsRn1uB1This will typically cause the user-agent (e.g. browser) to issue a
GET
to your registered Redirect URI.GET /receiveAuthCode?code=ilWsRn1uB1 HTTP/1.1
Host: MyAppServer.comYour application should save the Authentication Code from the querystring
code
variable. However, if an error occurred during the process (e.g. the user choses not to authorise the request), your application will receive a querystring containing anerror
variable instead. - Handling errors
-
If the user choses not to authorise your application's request for access, or if some other error occurs during the request process, the user-agent (e.g. browser) will be redirected to your registered Redirect URI containing an
error
variable, and no Authorisation Code will be included.Example:
GET /receiveAuthCode?error=access_denied&error_uri=https%3A%2F%2Flogin.huddle.net%2Fdocs%2Ferror%23AuthRequestAccessDenied HTTP/1.1
Host: MyAppServer.comThe
error_uri
variable contains the address of a document which explains the error in more detail. The possible values of theerror
variable are defined in the OAuth specification, and are summarised as follows:Error code Meaning invalid_request The request is missing a required parameter, includes an unsupported parameter or parameter value, or is otherwise malformed. invalid_client The client identifier provided is invalid. redirect_uri_mismatch The redirection URI provided does not match a pre-registered value1 access_denied The end-user or authorization server denied the request. unsupported_response_type The requested response type is not supported by the authorization server. Note that error codes
invalid_scope
andunauthorized_client
are not used by Huddle. - Sample code (C#)
-
In this sample we have created a class named HuddleAuthServiceAgent which is responsible for interactions with the Huddle OAuth server defined by the OAuth protocol
public class HuddleAuthServiceAgent
{
public HuddleAuthServiceAgent(IHuddleAuthConfiguration huddleAuthConfiguration)
{ HuddleAuthConfiguration = huddleAuthConfiguration; }
private IHuddleAuthConfiguration HuddleAuthConfiguration { get; set; }
public void BeginRequestEndUserAuthorisation(HttpContextBase httpContext)
{ var registeredRedirectUri = HuddleAuthConfiguration.RegisteredRedirectUri;
var huddleAuthServer = HuddleAuthConfiguration.HuddleAuthServer;
var registeredClientId = HuddleAuthConfiguration.RegisteredClientId;
var path = String.Format(
"{0}request?response_type=code&client_id={1}&redirect_uri={2}",
huddleAuthServer,
registeredClientId,
registeredRedirectUri
);
httpContext.Response.Redirect(path);
}
. . .
}
This can be called to initialise the access token request. For example, the following snippet could be executed from within an ASP.NET page code-behind file:
private void RequestEndUserAuthorisation()
{
// The user's browser will be redirected to Huddle's Authorisation server which will
// then redirect the user back to the registered redirect URI (from web.config) with
// an authorisation code
var authAgent = new HuddleAuthServiceAgent(new HuddleAuthConfiguration());
authAgent.BeginRequestEndUserAuthorisation(new HttpContextWrapper(Context)); }
3.Obtaining Access and Refresh tokens
How to use your authorisation code to obtain Access and Refresh tokens
Once you receive an authorisation code, you should request an Access token (and its accompanying Refresh token) from the server. The Access token is the piece of data which proves your authorisation to access data on behalf of the user. This Access token expires after a set period of time (typically five minutes) and must be refreshed by calling back to the authorisation server using the Refresh token.
Reference: OAuth 2.0 Specification, Sections: 4 , 4.1 , 4.1.1 , 4.2 ,
4.3 , 4.3.1
- Initial Request
-
Once your application has a valid authorisation code, it can obtain an Access token (and associated Refresh token) by POSTing to the
token
endpoint, as follows:POST /token HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=s6BhdRkqt&redirect_uri=MyAppUri%3A%2F%2FMyAppServer.com/receiveAuthCode&code=i1WsRn1uB1The variables in the body should be replaced with values specific to your application, with the exception of
grant_type
(and of coursecode
, which the server has supplied):Key Value grant_type Should be authorization_code
. Other values are not supported.client_id This should be your registered Client ID redirect_uri This should be your registered Redirect URI 1
code The Authorization Code received from the server 1 Note that although you MUST include the
redirect_uri
value, the Access token will be returned in the body of the server's immediate response - not by using your redirect_uri. The redirect_uri value will be verified against your registered Redirect URI to help verify that the client application still corresponds to the details originally registered for the specificedclient_id
. - Typical response
-
If the Authentication code is determined to be valid by the server, a standard HTTP 200 response will be received, including the token data as the entity body of the response using the
application/json
media type:HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token":"S1AV32hkKG",
"expires_in":300,
"refresh_token":"8xLOxBtZp8"
}
Details of these parameters (including
scope
- which Huddle does not currently use for external access). Note that theexpires_in
variable expresses the "time-to-live" of the access token, expressed in seconds. After the token expires, it must be refreshed (see "5. Refreshing your Access token" below) - Handling errors
-
If the token request is invalid or unauthorized, an HTTP 400 response will be received. This response also contains data encoded using the
application/json
media type.Example:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
"error":"invalid_grant",
"error_description":"The authorisation grant was revoked",
"error_uri":"https://login.huddle.net/docs/error#TokenRequestInvalidGrant"
}
The
error
value supplied is a single error code as described in section 4.3.1 of the OAuth 2.0 specification. A summary of the possible error codes is included:Error code Meaning invalid_request The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats a parameter, or is otherwise malformed. invalid_client The client identifier provided is invalid, or attempted to use an unsupported credentials type. unauthorized_client The client is not authorized to use the access grant type provided. invalid_grant The provided access grant is invalid, expired, or revoked (e.g. expired authorization token, or mismatching authorization code and redirection URI). unsupported_grant_type The access grant included - its type or another attribute - is not supported by the authorization server. invalid_scope The requested scope is invalid, unknown, or malformed. - Sample code (C#)
-
In this first piece of code, we process an incoming request to our registered Redirect URI.
var huddleAuthServiceAgent = new HuddleAuthServiceAgent(new HuddleAuthConfiguration());
HuddleAuthCode code;
try
{ code = huddleAuthServiceAgent.EndRequestEndUserAuthorisation(new HttpContextWrapper(Context)); }
catch (HuddleAuthException hex)
{ Log.Error(hex.PrettyPrint());
throw; }
The
huddleAuthServiceAgent.EndRequestEndUserAuthorisation
call simply passes the httpContextBase to the constructor of a class calledHuddleAuthCode
was created to parse the return message from the server:public class HuddleAuthCode
{
private const int MAX_NETWORK_LATENCY_IN_SECONDS = 10;
public HuddleAuthCode(HttpContextBase context)
{
Received = context.Timestamp;
CatchErrorResponse(context, "Processing the authorisation code return message from the server");
this.Value = context.Request["code"];
var expiresIn = context.Request["expires_in"];
int expiresInSeconds;
if (int.TryParse(expiresIn, out expiresInSeconds))
{
ExpiresOn = Received.AddSeconds(expiresInSeconds - MAX_NETWORK_LATENCY_IN_SECONDS); } }
public string Value { get; set; }
public DateTime Received { get; set; }
public DateTime? ExpiresOn { get; set; }
private static void CatchErrorResponse(HttpContextBase context, string protocolStage)
{ var errorCode = context.Request["error"];
if (string.IsNullOrEmpty(errorCode))
{
return; }
var errorDescription = context.Request["error_description"];
var errorUri = context.Request["error_uri"];
throw new HuddleAuthException()
{ ProtocolStage = protocolStage,
ErrorCode = errorCode,
ErrorDescription = errorDescription,
ErrorUri = errorUri }; }
}
Once the authorisation code is successfully received, we use another method on the
HuddleAuthServiceAgent
to call back to the auth server for the access token:public HuddleAccessToken ObtainAccessToken(WebClient client, HuddleAuthCode authCode)
{ var data = string.Format( "client_id={0}&grant_type=authorization_code&authorization_code={1}&redirect_uri={2}",
HuddleAuthConfiguration.RegisteredClientId,
authCode.Value,
HuddleAuthConfiguration.RegisteredRedirectUri );
var url = string.Format("{0}token", HuddleAuthConfiguration.HuddleAuthServer);
client.Headers.Add("Accept", "application/json");
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var tokenResponse = client.UploadString(url, data);
var ret = HuddleAccessToken.Parse(tokenResponse, DateTime.Now);
return ret; }The
HuddleAccessToken.Parse
factory method handles the parsing of the access token response:public static HuddleAccessToken Parse(string accessTokenRequestResponse, DateTime received)
{ var responseDictionary = (IDictionary)JsonConvert.Import(accessTokenRequestResponse);
var ret = new HuddleAccessToken() { Received = received };
var exception = new HuddleAuthException() { ProtocolStage = "Parsing json token response from server" };
if (!TryConvertResponse(responseDictionary, ret, exception))
{
throw exception; }
return ret; }
private static bool TryConvertResponse(IDictionary responseDictionary, HuddleAccessToken token, HuddleAuthException exception)
{ var setters = new Dictionary<string, Action<object>> { { "error", v => exception.ErrorCode = (string)v },
{ "error_description", v => exception.ErrorDescription = (string)v },
{ "error_uri", v => exception.ErrorUri = (string)v },
{ "access_token", v => token.Value = (string)v },
{ "refresh_token", v => token.RefreshToken = (string)v },
{ "expires_in", v => { int expiresInSeconds;
if (int.TryParse(v.ToString(), out expiresInSeconds))
{ token.ExpiresOn = token.Received.AddSeconds(expiresInSeconds - MAX_NETWORK_LATENCY_IN_SECONDS); } } } };
foreach (var entry in setters.Where(entry => responseDictionary.Contains(entry.Key)))
{ entry.Value(responseDictionary[entry.Key]); }
return string.IsNullOrEmpty(exception.ErrorCode); }
4.Calling the Huddle APIs
How to use your Access token when calling the API
On every call to Huddle APIs, your should include your access token as prove of your authorisation to access data on the end-user's behalf. Your application should be able to respond to error messages resulting from problems with the token.
Reference: OAuth 2.0 Specification, Sections: 5 , 5.1 , 5.1.1 , 5.2 ,
5.2.1
- Including your token in the request
-
While you hold an un-expired access token, you can gain access to data through the Huddle APIs by including the token in the Authorization header field of HTTP requests.
GET https://api.huddle.net/v2/calendar/workspaces/all HTTP/1.1
Authorization: OAuth2 vF9dft4qmT
Accept: application/xml
Host: api.huddle.net
Alternatively, the token may be passed as a querystring parameter:
GET https://api.huddle.net/v2/calendar/workspaces/all?oauth_token=vF9dft4qmT HTTP/1.1
Accept: application/xml
Host: api.huddle.net
- Handling errors
-
As required by the OAuth specification, if the request contains an invalid access token, or is malformed, the response from the server will be a 400 Bad Request, 401 Unauthorized or 403 Forbidden response, including a WWW-Authenticate header.
Example:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: OAuth2 error='expired-token'
The
error_uri
variable contains the address of a document which explains the error in more detail. The possible values of theerror
variable are defined in the OAuth specification, and are summarised as follows:Error code Meaning HTTP Status code invalid_request The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed. 400 expired_token The access token provided has expired. 401 N.B. Although the OAuth2 specification also defines the error codes
invalid_token
andinsufficient_scope
, these codes are never returned by Huddle's APIs. - Sample code (C#)
-
Once the token has been retrieved, we call the Huddle API using a method named
CallAPIEndpoint:
private static string CallAPIEndpoint(HuddleAccessToken token, string apiEndpointUrl)
{ var webClient = new WebClient();
token.SetAuthorizationHeader(webClient);
return webClient.DownloadString(apiEndpointUrl); }
This code uses a method on the
HuddleAuthToken
class namedSetAuthorizationHeader
:public void SetAuthorizationHeader(WebClient client)
{
client.Headers.Add("Authorization", "OAuth " + Value);
}
5.Refreshing your Access token
How to use your Refresh Token when your Access token expires
By calling the Authorisation and providing your Refresh token, you can obtain new tokens. You will need to do this preiodically as the access tokens expire after a short period of time (typically twenty minutes). Your application should account for the possibility that the end-user has deauthorised your application in the period since you last called the authorisation server.
Reference: OAuth 2.0 Specification, Sections: 4.1.4 , 4.2 , 4.3 ,
4.3.1
- Requesting fresh tokens
-
Developers are encouraged to monitor the "time-to-live" of their access tokens and to refresh their tokens before they expire. However, if an expired token is issued with an API call, the API will reject the access request with the
expired_token
code (see "4. Calling the Huddle APIs, Handling errors").Expired tokens can be refreshed using a request which is similar to the original access token request:
POST /refresh HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&client_id=s6BhdRkqt&refresh_token=n4E9O119d
The typical response and error handling for a
refresh_token
access grant request is identical to that of the originalauthorization_code
request (see "3. Obtaining Access and Refresh tokens, Typical response" and "3. Obtaining Access and Refresh tokens, Handling errors") - Sample code (C#)
- blah blah