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 #1Blog Center PHP App
is an separate app running somewhere that has Client Credentials #2Android 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 Tokenrefresh_token
is the Refresh Tokenexpires_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 theAuthorization
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 -
- 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.
- 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:
- Create a Project
- Click on
Manage Project
- Select
Applications
from the left-hand menu - Click
New Application
- 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:
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.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,
acode
will be passed back to this URI. For example, if you set this tohttp://server.com/auth/callback
, then
CloudCMS will redirect the successfully authenticated user to:
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
is9e29558b-9f9f-43e5-926e-781e983afe52
clientSecret
isrQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/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
isrQCzxeKLQYyP3hHDwuAVVrTosQhth57bvBzVfootKHyzA/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.