Authentication

Cloud CMS supports authentication via the industry standard OAuth 2.0 protocol.

OAuth 2.0 is a well-recognized standard that enables client code to connect to Cloud CMS in a secure and safe fashion. This means that authorization can be achieved in such a way that client and user credentials (secret keys) are never publicly exposed. Channel-level encryption is provided by HTTPS and HTTP POST payloads are utilized to avoid exposure of credentials via request parameters or logging facilities.

For more insight into what OAuth 2.0 is and how it works, check out a somewhat eclectic yet insightful description of OAuth 2.0.

From an OAuth 2.0 perspective, Cloud CMS provides both an Authorization Server and a Resource Server. Cloud CMS supports two-phase support for the OAuth 2.0 Authorization Code Grant as well as the single-phase Resource Password Grant. It also supports optional Refresh Tokens for either of these flows so as to allow continuity of Access Token exchange.

Cloud CMS requires an authenticated Client and authenticated User for all API interactions. As such, Cloud CMS does not support the Client Credentials Grant and it also does not support Implicit Grant.

Credentials / Tokens

Cloud CMS adhere strictly to OAuth 2.0 and, in that spirit, there are two sets of credentials that Cloud CMS requires in order to issue an Access Token. An Access Token is a bit of a text that you must supply with every API call to Cloud CMS after you log in.

In order to get an Access Token, you must supply:

  • Client Credentials
  • User Credentials

The Client Credentials are issued to the Application. They identify the Application that is attempting to connect to Cloud CMS. The User Credentials, in turn, identify the User to be authenticated.

One way to think of this is to think of Cloud CMS as having a door. The door has two locks on it. In order to open the door, both locks must be unlocked. One lock is the Client lock. And the other is the User lock.

The Application must submit Client credentials that match the first lock. And the User must submit User credentials that match the second lock.

In this fashion, every connection into Cloud CMS is a connection as a user using a given application. For example:

  • David Gilmour connects to Cloud CMS from Public Web Site
  • Richard Wright connects to Cloud CMS from Blog Center PHP App
  • Nick Mason connects to Cloud CMS from Android App 1.0

Where:

  • Public Web Site is an separate app running somewhere that has Client Credentials #1
  • Blog Center PHP App is an separate app running somewhere that has Client Credentials #2
  • Android App 1.0 is an separate app running somewhere that has Client Credentials #3

Each Client Credentials consists of:

  • Client Key (clientKey)
  • Client Secret (clientSecret)

Similarly, each logging in user has their own credentials, consisting of:

  • Username (username)
  • Password (password)

Once Cloud CMS receives both the Client and User Credentials, it will authenticate the user. And it will then hand back an Access Token and, optionally, a Refresh Token. The response will look something like this:

{
  "access_token" : "5c69c1cf-7d8d-4749-ae04-74d7b2862741",
  "token_type" : "bearer",
  "refresh_token" : "d5098c88-e414-4c42-a078-b49dd3e6b458",
  "expires_in" : 86399,
  "scope" : "api"
}

Where:

  • access_token is the Access Token
  • refresh_token is the Refresh Token
  • expires_in is the time until the Access Token expires (in seconds)

Access Token and Refresh Token

Once you've successfully provided your credentials to Cloud CMS, you will be given an Access Token and a Refresh Token. Your invoking code should remember these tokens by whatever means you prefer. The Access Token, in particular, will need to be provided will every subsequent call to Cloud CMS.

Access Token

The Access Token must be supplied with every API call to Cloud CMS. It is typically passed with each call via the Authorization header, like this:

Authorization: bearer 5c69c1cf-7d8d-4749-ae04-74d7b2862741

Where 5c69c1cf-7d8d-4749-ae04-74d7b2862741 is the Access Token from above. Be sure to pass in whatever value you receive back when you authenticate.

On the API side, Cloud CMS looks at the incoming Access Token and uses it to look up who the authenticated User is. It then allows the call to proceed on on behalf of the authenticated User.

By default, an Access Token is only valid for 24 hours. Once the validity period expires, the Access Token will no longer work and you will receive 401 errors on your HTTP calls.

You can customize the Access Token validity period from within the user interface (Manage Platform). On-premise users can also adjust the default value at the Docker configuration level.

Once your Access Token is invalid, you have two options -

  1. Re-authenticate by passing the Client Credentials and User Credentials all over again. You will be issued a new Access Token to use for subsequent requests.
  2. If you were issued a Refresh Token, you can pass the Refresh token over to acquire a new Access Token. This saves you the trouble of having to re-submit the Client Credentials and User Credentials all over again.

We strongly recommend #2. The idea with a Refresh Token is that it saves you the problem of having to somehow re-acquire the user's login information. This usually involves re-prompting the user for their login information. It's less than ideal in many circumstances.

Refresh Token

If your Access Token expires, you can use the Refresh Token to get a new one. The same Refresh Token can be used repeatedly to acquire new Access Tokens until the Refresh Token itself expires.

By default, a Refresh Token is valid for one year. Once the refresh token period expires, it will no longer be able to be used to acquire new Access Tokens. And instead, you will have to perform a full re-authentication using your API Keys.

You can customize the Refresh Token validity period from within the user interface (Manage Platform). On-premise users can also adjust the default value at the Docker configuration level.

If your Refresh Token expires, the only option you have is to re-authenticate using the Client and User Credentials.

From a practical perspective, this is rarely an issue since a 1 year validity period is usually a long enough period of time such that your application will be updated, redeployed or at least restarted at some point. In these cases, the app would have logged in again long before the Refresh Token expired.

API Keys

Cloud CMS lets you create API Keys for use in authenticating with OAuth 2.0.

You create API Keys by creating a Client instance and, optionally, an Authentication Grant instance.

A Client instance defines the Client Credentials that an external application would use to connect. This includes the clientKey and clientSecret credentials but also includes a number of other factors that you can set up to limit and constrain connectivity for the Client.

For example,

  • You can limit what OAuth 2.0 Grant Types are permitted using this Client (Authorization Code, Password, Refresh Token)
  • You can adjust the validity period of Access Tokens and Refresh Tokens issued for the Client
  • You can change the display title, description, image icon and other access confirmation attributes

And most importantly, you can disable the Client at any time if you detect abuse or if you feel the Client keys may have been compromised.

An Authentication Grant instance defines an optional set of User Credentials that an external application user would use to connect. This includes the username and password credentials.

Authentication Grants are optional because, technically, all your need is a Client and then anyone can log in using that Client with their own username and password. However, there are times where you might want to have your application connect as an "app user" or a pre-defined user and you may not want the username and password released into the wild.

For those cases, you will be better suited to create an Authentication Grant. This gives you an alternative set of User Credentials that ultimately let the invoker log in as the very same app user. The benefit here is that you can apply some constraints and limits to the Authentication Grant. For example,

  • You can limit which Client the Authentication Grant can be used with
  • You can disable Authentication Grants at any time if you detect abuse or feel that the Authentication Grant keys may have been compromised.

As such, API Keys are actually comprised of a Client (at a minimum) or a Client + Authentication Grant.

A full set may look like this:

{
    "clientKey": "9e29558b-9f9f-43e5-926e-781e983afe52",
    "clientSecret": "rQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/IiwcRtpOLROjKwOkzOO5DPgH1PAaN3eUkn9QVsv/fFtecohUPtjenByN6XeRw=",
    "username": "0d1d0e4a-64c8-4878-9a85-1118115fb47c",
    "password": "/HtKGjBSeMvWMGQ79fHpgOT/UvKxZePQeN1ZpHaxMj1BkeOhWWFgytSk1ZJ+JJv42CdVKRatyYrodVmn3l2LlgbKGumKnmAiLwV1FZ9Yjqw="
}

Where a Client contributes clientKey and clientSecret and an Authentication Grant contributes username and password.

Or you may use a reduced set if the user provides their credentials via other means, i.e.:

{
    "clientKey": "9e29558b-9f9f-43e5-926e-781e983afe52",
    "clientSecret": "rQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/IiwcRtpOLROjKwOkzOO5DPgH1PAaN3eUkn9QVsv/fFtecohUPtjenByN6XeRw="
}

Creating API Keys

There are two ways to create API Keys.

The first way is to create a new Application instance within Cloud CMS. Every Application comes with its own set of API Keys that provide a new Client and a new Authentication Grant.

The Authentication Grant is pre-wired to an application user that is generated when you create your Application.
This application user has read and write privileges across the Project to which your Application belongs.

To do this:

  1. Create a Project
  2. Click on Manage Project
  3. Select Applications from the left-hand menu
  4. Click New Application
  5. Give your Application a title and click Create

Then click on API Keys under the Developers section in the left-hand menu. You will see something like:

Click on gitana.json to see the keys in a format that is compatible with one of our many drivers:

So that's one way to create API Keys.

Another way is to manually create a Client and an Authentication Grant.

Creating a Client

We recommend creating a different Client for each unique external application that calls into Cloud CMS.

To do so, go to the Administration Console. When you log in, you will see Clients on the left-hand side.

Click on it and you will then be shown a list of your Client instances:

Click on Create to create a new Client. Give it a Title and a Description (at a minimum).

And click Create Client. You will then be taken to an overview of your Client where you will be able to see the Client Key and Client Secret values.

By default, newly created Clients support all of the Grant Types (Authorization Code, Client Credentials, Password and Refresh Token). You can adjust this as you see fit.

If you wish to use the Authorization Code Grant Type, you will additionally need to provide:

  • Registered Redirect URI (required)
  • Auto Approval Scopes (optional)
  • Logo URL (optional)

More information about this is provided in a later portion of this document.

Authentication Grants

To create an Authentication Grant, go to the Administration Console and click on Authentication Grants on the left-hand side:

Click on it and you will then be shown a list of your Authentication Grant instances:

Click on Create to create a new Authentication Grant. Give it a Title and a Description. And then pick the Client that you would like to connect the Authentication Grant with. The Authentication Grant will only work with one Client.

Finally, pick the Principal that the Authentication Grant will log in as.

And click Create Authentication Grant. You will then be taken to an overview of your Authentication Grant where you will be able to see the Client Key and Client Secret values.

To learn more about API Keys, we recommend reading our formal API Keys documentation.

Grant Types

As mentioned, Cloud CMS needs to have the Client Credentials and User Credentials at hand in order to authenticate a user and hand back an Access Token. The trick is to figure out how to get this information to Cloud CMS in such a way that the clientSecret and password portions of the credentials cannot be hacked, stolen or spoofed.

OAuth 2.0 describes a number of Grant Types, each with their respective flow, that serve to guarantee security and reduce the attack surface area by would-be snoopers or otherwise mal-intentioned individuals.

Cloud CMS supports three of these OAuth 2.0 Grant Types. These are:

  • Resource Password (password)
  • Authorization Code (authorization_code)
  • Refresh Token (refresh_token)

Each Grant Type has its own flow and sequence and is suitable for a particular kind of application. There are described in greater detail below.

Cloud CMS does not support the the Implicit Grant Type. For an explanation and for more information on OAuth 2.0 best practices, please see https://tools.ietf.org/html/draft-ietf-oauth-security-topics-10.

Cloud CMS also does not support the Client Credentials Grant Type. With Cloud CMS, all API calls must be made on behalf of an authenticated user. The authenticated user's ACLs are checked meticulously against every object, container and resource that the user interacts with. There is no notion within Cloud CMS of a "client" credential by itself - rather, authenticated credentials are always user credentials (executing on behalf of a client).

Resource Password Grant Type

Let's start with the simplest Grant Type.

The Resource Password Grant is ideal for situations where your external application has its Client Credentials but also is in charge of collecting or otherwise knowing the User Credentials. Here are a few possibilities:

  1. Your external app might be a compiled mobile application where the Client and User Credentials are shipped in an encrypted properties file. The app loads this up and authenticates to Cloud CMS in a single "Resource Password" token grant.

  2. Your external app might be a Node.js middle tier where the Client credentials are shipped with the final distribution. The Node.js app presents a form to the end user where they enter their username and password. It then passes these User Credentials (along with the Client Credentials) to Cloud CMS in a single "Resource Password" token grant.

Note that in both of these cases, the Client's clientSecret and User's password are secure. In the former case, they are secure because they're stored within compiled code and encrypted. In the latter case, they can be made to be secure if the Node app utilizes TLS and best practices for authenticated sessions (within a framework such as Express or using the Cloud CMS application server). Further, the Node.js server runs in a middle tier that the end user does not have access to. The form submit where the password is sent is transient and the password itself is never retained by the front-end browser.

In neither of these cases can the end user gain access to the clientSecret or the password.

For cases such as these, we recommend using the Resource Password Grant Type.

With this grant type, you pass all of the client information (Client Key and Client Secret) and all of the user information (Username and Password) over to Cloud CMS at the same time. Cloud CMS authenticates the Client and the User at the same time and then hands back an Access Token and Refresh Token.

The Resource Password Grant should only be used within applications that have high security standards. For example, you might use the Resource Password Grant within compiled tools, standalone apps or other places where the source code is not visible to the end user. Since this grant type groups the Client Secret and User Password together into the same place, it's very important that these values not be discovered.

WARNING: The Resource Password Grant should not be used via Ajax calls within the browser. If you're making Ajax calls from the browser directly to Cloud CMS, then you must be putting your Client Secret and User Password into the source of your JavaScript. And that can be snooped by malicious parties. Instead, for Ajax calls that initiate within the browser and wish to connect to Cloud CMS, we recommend either the Authorization Code grant type or potentially connecting to a middle tier API.

Usage

To use the Resource Password Grant type, make sure your Client has password as a Authorized Grant Type.

Here is an image that essentially shows how this flow works:

1. The application ("client") passes the Client Key, Client Secret, Username and Password to Cloud CMS.

This is done by opening up an HTTP POST request to:

POST /oauth/token?grant_type=password&username=USERNAME&password=PASSWORD

Where USERNAME and PASSWORD comprise the User's credentials. The HTTP POST should also have an Authorization header that conforms to Basic Authentication standards. Its value should be:

basic BASE64STRING

Where BASE64STRING is the result of converting CLIENT_KEY:CLIENT_SECRET to Base 64. CLIENT_KEY and CLIENT_SECRET comprise the Client's credentials.

2. Cloud CMS authenticates the client and the user at the same time. It then issues an Access Token and Refresh Token. The Access Token and Refresh Token are handed back via a JSON payload.

The payload may look something like this:

{
  "access_token" : "5c69c1cf-7d8d-4749-ae04-74d7b2862741",
  "token_type" : "bearer",
  "refresh_token" : "d5098c88-e414-4c42-a078-b49dd3e6b458",
  "expires_in" : 86399,
  "scope" : "api"
}

Where the values for access_token and refresh_token should be retained by your application and then applied to every subsequent request to the Cloud CMS API.

Authorization Code Grant Type

And now let's look at the most secure Grant Type.

The Authorization Code grant is the most secure grant type because it provides a way for the User Credentials to be supplied in a way that the Client application never learns about them. This means that the external application itself never has a chance to intercept the username or password at all.

With this approach, your external application does not need to provide its own login form. Essentially, your application will redirect to an external login form (provided by Cloud CMS) where the user logs in. Once they've logged in, they will be redirected back to your app along with a code. Your application can then pass its Client Credentials over to Cloud CMS along with the code.

Cloud CMS will then authenticate the Client Credentials and validate the code. If the code checks out, an Access Token will be sent back to your external application.

We recommend this Grant Type for any web sites or HTTP-based applications that need to establish authenticated state within the browser. This Grant Type is also practical for web applications where authenticated is maintained on the server side (but requires the user to provide their Cloud CMS credentials).

Usage

To use the Authorization Code flow, you will need to make sure that your client has authorization_code as an Authorized Grant type.

In addition, you will need to provide:

  • Registered Redirect URI - this should be a URI within your web application. When the user successfully signs in, a code will be passed back to this URI. For example, if you set this to http://server.com/auth/callback, then CloudCMS will redirect the successfully authenticated user to:

    http://server.com/auth/callback?code=CODE

Where CODE is the transient code used in the Authorization Code flow.

You may also wish to provide the following:

  • Logo URL - this is an optional URL to a logo that will be displayed on the Cloud CMS form that the user interacts with to provide their username and password. This form displays the Client title and Client description, allowing you to inform the user about which application is requesting them to log in. The logo URL, if provided, will display an image for your application.

After the user logs in, they may be taken to a page that allows them to confirm access for the application. This is a distinct step since a single user may authenticate via many applications. An access confirmation page will ask the user whether they approve the application receiving an Access Token representing the user.

If you wish to simply the process and skip this step, you can configure the Client to have the Auto Approval Scope of api. This will simplify the access confirmation by simply skipping past it. Approval will be automatically provided and the CODE will be handed back right away.

Let's take a look at an example.

Suppose we have a web site that lives at https://www.mysite.com.

We create a Client instance with:

  • clientKey is 9e29558b-9f9f-43e5-926e-781e983afe52
  • clientSecret is rQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/IiwcRtpOLROjKwOkzOO5DPgH1PAaN3eUkn9QVsv/fFtecohUPtjenByN6XeRw=

The flow looks like this:

Here is how it works:

1. We can start the Authorization Code Grant by adding a button to our web site that says "Log In". When users click that button, we take them here:

https://api.cloudcms.com/oauth/authorize?response_type=code&scope=api&client_id=9e29558b-9f9f-43e5-926e-781e983afe52&redirect_uri=https://www.mysite.com/callback

Where client_id is the Client Key and https://www.mysite.com/callback is a route that we control where we expect the code to be sent back once the user authenticates.

Their browser now goes to that URL and they are presented with a form that looks like this:

They fill in their username and password. And then they click Submit.

They are then taken to an Access Confirmation screen. This screen makes sure they want to share their authenticated state with the application that is requesting it.

They click Authorize .

2. A code is then generated and handed back to the application at the redirect_uri specified above. The code is handed back in the query string of the URL, like this:

https://www.mysite.com/callback?code=Gz6Afh

Where Gz6Afh is the code being handed back.

3. Our application has a route listening at /callback that picks up this code and then uses it to acquire an Access Token.

It makes an HTTP POST call to request a token. This URL looks like:

POST /oauth/token?grant_type=authorization_code&scope=api&redirect_uri=https://www.mysite.com&code=Gz6Afh

Where Gz6Afh is the code we received in Step 2. The HTTP POST should also have an Authorization header that conforms to Basic Authentication standards. Its value should be:

basic BASE64STRING

Where BASE64STRING is the result of converting CLIENT_KEY:CLIENT_SECRET to Base 64. CLIENT_KEY and CLIENT_SECRET comprise the Client's credentials.

In this way, we effectively pass the Client Key, Client Secret and Code over to Cloud CMS.

In this example, our clientKey is 9e29558b-9f9f-43e5-926e-781e983afe52 and our clientSecret is rQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/IiwcRtpOLROjKwOkzOO5DPgH1PAaN3eUkn9QVsv/fFtecohUPtjenByN6XeRw=. As such, we want to compute the Base64 string of:

9e29558b-9f9f-43e5-926e-781e983afe52:rQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/IiwcRtpOLROjKwOkzOO5DPgH1PAaN3eUkn9QVsv/fFtecohUPtjenByN6XeRw=

Our application can compute the Base64 of this pretty easily. But for giggles, we can use an online service to verify. We recommend https://www.base64encode.org/.

The Base64 encoded value is:

OWUyOTU1OGItOWY5Zi00M2U1LTkyNmUtNzgxZTk4M2FmZTUyOnJRQ3p4ZUtMUVl5UDNoSER3dUFWVnJUb3NRaHRoNTdidkJ6VmZvb3RLSHl6QS9JaXdjUnRwT0xST2pLd09rek9PNURQZ0gxUEFhTjNlVWtuOVFWc3YvZkZ0ZWNvaFVQdGplbkJ5TjZYZVJ3PQ==

As such, we should set the Authorization header to:

basic OWUyOTU1OGItOWY5Zi00M2U1LTkyNmUtNzgxZTk4M2FmZTUyOnJRQ3p4ZUtMUVl5UDNoSER3dUFWVnJUb3NRaHRoNTdidkJ6VmZvb3RLSHl6QS9JaXdjUnRwT0xST2pLd09rek9PNURQZ0gxUEFhTjNlVWtuOVFWc3YvZkZ0ZWNvaFVQdGplbkJ5TjZYZVJ3PQ==    

We make the HTTP POST call over to Cloud CMS passing this basic authorization header.

4. Cloud CMS validates the Client Key and Client Secret. It then takes the code and checks to make sure it is valid as well. It then looks up the user who is described by the code and authenticates as that user.

5. An Access Token and a Refresh Token are created.

6. Cloud CMS responds and hands the Access Token and Refresh Token back to your application.

The response may look something like this:

{
  "access_token" : "5c69c1cf-7d8d-4749-ae04-74d7b2862741",
  "token_type" : "bearer",
  "refresh_token" : "d5098c88-e414-4c42-a078-b49dd3e6b458",
  "expires_in" : 86399,
  "scope" : "api"
}

These values should be retained and the Access Token should then be applied to every subsequent request to the API.

Refresh Token Grant

If your Client is configured to allow for the Refresh Token Grant, then a Refresh Token will be generated along with the Access Token for either the Authorization Code or the Resource Password Grant Types.

The JSON response will contain a Refresh Token - like this:

{
  "access_token" : "5c69c1cf-7d8d-4749-ae04-74d7b2862741",
  "token_type" : "bearer",
  "refresh_token" : "d5098c88-e414-4c42-a078-b49dd3e6b458",
  "expires_in" : 86399,
  "scope" : "api"
}

If the Refresh Token Grant is not enabled, you'll get back a simpler response, like this:

{
  "access_token" : "5c69c1cf-7d8d-4749-ae04-74d7b2862741",
  "token_type" : "bearer",
  "expires_in" : 86399,
  "scope" : "api"
}

If a Refresh Token was granted, it should be retained by your application for future use. If your Access Token expires or if you decide to pre-emptively acquire a new access token (perhaps based on the expires_in value), you can use the Refresh Token to acquire a new Access Token.

To do so, you will need to send an HTTP POST request like this:

POST /oauth/token?grant_type=refresh_token&refresh_token=d5098c88-e414-4c42-a078-b49dd3e6b458

Where:

  • d5098c88-e414-4c42-a078-b49dd3e6b458 is the Refresh Token from above

The response will be a JSON object with the new Access Token:

{
  "access_token" : "2741ae04-7dc1-d749-8dcf-7447b2865c69",
  "token_type" : "bearer",
  "refresh_token" : "d5098c88-e414-4c42-a078-b49dd3e6b458",
  "expires_in" : 86399,
  "scope" : "api"
}

Direct Login

You can log in directly to the API server by going to:

http://api.cloudcms.com/login

You will presented with a login form that looks like this:

You will need to provide:

  • Client Key
  • Client Secret
  • Username
  • Password

If you authenticate successfully, you will be routed back to

http://api.cloudcms.com

And you will have an HTTP Cookie set. The cookie's name is GITANA_TICKET. It is a JWT encoded cookie that authenticates the browser session to the API.