OpenStackID APIs use the OAuth 2.0 protocol for authorization. OpenStackID supports common OAuth 2.0 scenarios such as those for web server, Service Accounts, and client-side applications. OAuth 2.0 is a relatively simple protocol. To begin, you register your application with OpenStackID. Then your client application requests an access token from the OpenStackID Authorization Server, extracts a token from the response, and sends the token to the OpenStackID API that you want to access.
All applications follow a basic pattern when accessing an OpenStackID API using OAuth 2.0. At a high level, you follow four steps:
The OpenStackID OAuth 2.0 endpoint supports web server applications that use languages and frameworks such as PHP, Java, Python, Ruby, and ASP.NET. These applications might access an OpenStackID API while the user is present at the application or after the user has left the application. This flow requires that the application can keep a secret.
The authorization sequence begins when your application redirects a browser to the OpenStackID OAuth 2.0 Endpoint; the URL includes query parameters that indicate the type of access being requested.The result is an authorization code, which OpenStackID returns to your application in a query string. After receiving the authorization code, your application can exchange the code (along with a client ID and client secret) for an access token and, in some cases, a refresh token. The application can then use the access token to access an OpenStackID API. If a refresh token is present in the authorization code exchange, then it can be used to obtain new access tokens at any time. This is called offline access, because the user does not have to be present at the browser when the application obtains a new access token.
The URL used when authenticating a user is https://openstackid.org/oauth2/auth. This endpoint is accessible over SSL, and HTTP connections are refused. This endpoint is the target of the initial request. It handles active session lookup, authenticating the user, and user consent. The result of requests to this endpoint include access tokens, refresh tokens, and authorization codes.
The set of query string parameters supported by the OpenStackID Authorization Server for web server applications are:
Parameter | Values | Description |
---|---|---|
response_type | code | Determines whether the OpenStackID OAuth 2.0 endpoint returns an authorization code. Web server applications should use code. |
client_id | The client ID you obtain from the OpenStackID OAUTH2 Console when you register your app. | Identifies the client that is making the request. The value passed in this parameter must exactly match the value shown in the OpenStackID OAUTH2 Console. |
redirect_uri | One of the redirect_uri values registered at the OpenStackID OAUTH2 Console. | Determines where the response is sent. The value of this parameter must exactly match one of the values registered in the OpenStackID OAUTH2 Console (including https scheme, case, and trailing ‘/’). |
scope | Space-delimited set of permissions that the application requests. | Identifies the OpenStackID API access that your application is requesting. The values passed in this parameter inform the consent screen that is shown to the user. |
state | Any string | Provides any state that might be useful to your application upon receipt of the response. The Openstack Authorization Server roundtrips this parameter, so your application receives the same value it sent. Possible uses include redirecting the user to the correct resource in your site, nonces, and cross-site-request-forgery mitigations. |
access_type | online or offline | Indicates whether your application needs to access an OpenStackID API when the user is not present at the browser. This parameter defaults to online. If your application needs to refresh access tokens when the user is not present at the browser, then use offline. This will result in your application obtaining a refresh token the first time your application exchanges an authorization code for a user. |
approval_prompt | force or auto | Indicates whether the user should be re-prompted for consent. The default is auto, so a given user should only see the consent page for a given set of scopes the first time through the sequence. If the value is force, then the user sees a consent page even if they previously gave consent to your application for a given set of scopes. |
The response will be sent to the redirect_uri as specified in the request URL. If the user approves the access request, then the response contains an authorization code and the state parameter (if included in the request). If the user does not approve the request, the response contains an error message. All responses are returned to the web server on the query string, as shown below:
An error response:
https://oauth2-demo.com/code?error=access_denied&state=xyz
An authorization code response:
https://oauth2-demo.com/code?state=xyz&code=123456
After the web server receives the authorization code, it may exchange the authorization code for an access token and a refresh token. This request is an HTTPS post, and includes the following parameters:
Parameter | Description |
---|---|
code | The authorization code returned from the initial request. |
client_id | The client ID obtained from the OpenStackID OAUTH2 Console during application registration. |
client_secret | The client secret obtained during application registration |
redirect_uri | The URI registered with the application. |
grant_type | As defined in the OAuth 2.0 specification, this field must contain a value of authorization_code. |
REMARK
It is advisable that you exclude client_id/client_secret params from query string and use instead the Authorization Header like this:
Authorization: Basic Base64-Encoded(client_id:client_secret)
The actual request might look like the following:
POST /oauth2/token HTTP/1.1
Host: OpenStackID.openstack.org
Authorization: Basic Base64-Encoded(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
A successful response to this request contains the following fields:
Field | Description |
---|---|
access_token | The token that can be sent to an OpenStackID API. |
refresh_token | A token that may be used to obtain a new access token. Refresh tokens are valid until the user revokes access. This field is only present if access_type=offline is included in the authorization code request. |
expires_in | The remaining lifetime of the access token in seconds. |
token_type | Identifies the type of token returned. At this time, this field will always have the value Bearer. |
An example successful response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
}
After your application obtains an access token, you can use the token to make calls to a OpenStackID API on behalf of a given user. To do this, include the access token in a request to the API by including either an access_token query parameter or an Authorization: Bearer HTTP header. When possible, it is preferable to use the HTTP Header, since query strings tend to be visible in server logs.
Examples
Here is a call to the same API for the authenticated user (me) using the access_token Authorization Bearer HTTP header:
GET /api/v1/users/me HTTP/1.1
Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg
Host: OpenStackID.openstack.org
In some cases, your application may need to access an OpenStackID API when the user is not present. This style of access is called offline, and web server applications may request offline access from a user. The normal and default style of access is called online. If your application needs offline access to an OpenStackID API, then the request for an authorization code should include the access_type parameter, where the value of that parameter is offline. The first time a given user’s browser is sent to this URL, they see a consent page. If they grant access, then the response includes an authorization code which may be redeemed for an access token and a refresh token. If this is the first time the application has exchanged an authorization code for a user, then the response includes an access token and a refresh token, as shown below:
{
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in":3600,
"token_type":"Bearer",
"refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
IMPORTANT:
When your application receives a refresh token, it is important to store that refresh token for future use. If your application loses the refresh token, it will have to re-prompt the user for consent before obtaining another refresh token. If you need to re-prompt the user for consent, include the approval_prompt parameter in the authorization code request, and set the value to force.
After your application receives the refresh token, it may obtain new access tokens at any time. The next time your application requests an authorization code for that user, the user will not be asked to grant consent (assuming they previously granted access, and you are asking for the same scopes). As expected, the response includes an authorization code which may be redeemed. However, unlike the first time an authorization code is exchanged for a given user, a refresh token will not be returned from the authorization code exchange.
The following is an example of such a response:
{
"access_token":"1/fFAGRNJru1FQd77BzhT3Zg",
"expires_in":3600,
"token_type":"Bearer"
}
As indicated in the previous section, a refresh token is obtained in offline scenarios during the first authorization code exchange. In these cases, your application may obtain a new access token by sending a refresh token to the OpenStackID OAuth 2.0 Authorization server. To obtain a new access token this way, your application performs an HTTPS POST to https://openstackid.org/oauth2/token. The request must include the following parameters:
Parameter | Description |
---|---|
refresh_token | (required) The refresh token returned from the authorization code exchange. |
grant_type | (required) As defined in the OAuth 2.0 specification, this field must contain a value of refresh_token. |
scope | (optional) The requested scope MUST NOT include any scope not originally granted by the resource owner, and if omitted is treated as equal to the scope originally granted by the resource owner. |
Such a request will look similar to the following:
POST /oauth2/token HTTP/1.1
Host: OpenStackID.openstack.org
Authorization: Basic Base64-Encoded(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
As long as the user has not revoked the access granted to your application, the response includes a new access token. A response from such a request is shown below:
{
"access_token":"1/fFBGRNJru1FQd44AzqT3Zg",
"expires_in":3600,
"token_type":"Bearer"
}
In some cases a user may wish to revoke access given to an application. A user can revoke access by visiting the following URL and explicitly revoking access: https://openstackid.org/admin/grants . It is also possible for an application to programmatically revoke the access given to it. Programmatic revocation is important in instances where a user unsubscribes or removes an application. In other words, part of the removal process can include an API request to ensure the permissions granted to the application are removed.
To programmatically revoke a token, your application makes a request to
https://openstackid.org/oauth2/token/revoke and includes the token as a parameter and a hint
Parameter | Description |
---|---|
token | (required) Token value to revoke |
token_type_hint | (optional) access_token/refresh_token Hint to allow Authorization Server to do a more performant token search |
The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked. If the revocation is successfully processed, then the status code of the response is 200. For error conditions, a status code 400 is returned along with an error code.
In OAuth 2.0, the contents of tokens are opaque to clients. This means that the client does not need to know anything about the content or structure of the token itself, if there is any. However, there is still a large amount of metadata that may be attached to a token, such as its current validity, approved scopes, and extra information about the authentication context in which the token was issued. These pieces of information are often vital to Protected Resources making authorization decisions based on the tokens being presented. Since OAuth2 defines no direct relationship between the Authorization Server and the Protected Resource, only that they must have an agreement on the tokens themselves, there have been many different approaches to bridging this gap.
OpenStackID Authorization Server implements OAuth Token Introspection to fix that gap.
To programmatically get info for a token, your application makes a request to
https://openstackid.org/oauth2/token/introspection
Such a request will look similar to the following:
POST /oauth2/token/introspection HTTP/1.1
Host: OpenStackID.openstack.org
Authorization: Basic Base64-Encoded(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
token=tGzv3JOkF0XG5Qx2TlKWIA
IMPORTANT
the token must belongs to clientid provided on the request, otherwise request will fail
The TokenInfo endpoint will respond with a JSON array that describes the token or an error. Below is a table of the fields included in the non-error case:
Parameter | Description |
---|---|
audience | The Resource Server that is the intended target of the token. |
access_token | Token Value |
client_id | The application that is the intended target of the token. |
scope | The space-delimited set of scopes that the user consented to. |
expires_in | The number of seconds left in the lifetime of the token. |
token_type | Identifies the type of token returned. At this time, this field will always have the value Bearer. |
userid | This field is only present if a resource owner (end-user) had approved access on the consent screen. |
application_type | identifies the client type. (WEB_APPLICATION, JS_CLIENT OR SERVICE ) |
allowed_return_uris | identifies the allowed return uris set for this client. |
allowed_origins | This field is only present if application_type == JS_CLIENT. identifies the allowed origin uris set for this client. |
A response from such a request is shown below:
{
"access_token":"1/fFBGRNJru1FQd44AzqT3Zg",
"client_id": "xyz",
"expires_in":3600,
"token_type":"Bearer",
"scope":"profile email",
"audience": "resource.server1.com",
"user_id": 123456,
"application_type": "WEB_APPLICATION",
"allowed_return_uris": "www.test.com",
"allowed_origins": "www.test1.com",
}
The OpenStackID OAuth 2.0 endpoint supports JavaScript-centric applications. These applications may access an OpenStackID API while the user is present at the application, and this type of application cannot keep a secret.
This scenario begins by redirecting a browser (full page or popup) to a OpenStackID URL with a set of query parameters that indicate the type of OpenStackID API access the application requires. As in other scenarios, OpenStackID handles user authentication and consent, and the result is an access token. OpenStackID returns the access token on the fragment of the response, and client side script extracts the access token from the response. The application may access an OpenStackID API after it receives the access token.
NOTE: Your application should always use HTTPS in this scenario.
OpenStackID returns an access token to your application if the user grants your application the permissions it requested. The access token is returned to your application in the fragment as part of the access_token parameter. Since a fragment is not returned to the server, client-side script must parse the fragment and extract the value of the access_token parameter. Other parameters included in the response include expires_in and token_type. These parameters describe the lifetime of the token in seconds, and the kind of token that is being returned. If the state parameter was included in the request, then it is also included in the response.
An example User Agent flow response is shown below:
https://oauth2-demo.com//oauthcallback#access_token=123456&token_type=Bearer&expires_in=3600
After your application obtains an access token, you can use the token to make calls to an OpenStackID API on behalf of a given user. To do this, include the access token in a request to the API by including either an access_token query parameter or an Authorization: Bearer HTTP header. When possible, it is preferable to use the HTTP Header, since query strings tend to be visible in server logs.
NOTE:
Be sure that OpenStackID Endpoint API that your application wants to access it’s been CORS enabled
Allows to get additional info about current user (Me)
Gets additional information about the current user
Example request:
GET /api/v1/users/me HTTP/1.1
Host: openstackid.org
Accept: application/json, text/javascript
Example response:
{
"name":"Sebastian",
"family_name":"Marcet",
"nickname":"Sebastian Marcet",
"picture":"http:\/\/www.openstack.org\/assets\/profile-images\/IMG-20140912-WA0003.jpg",
"birthdate":"",
"gender":"Male",
"email":"[email protected]"
}
The OpenStackID OAuth 2.0 Authorization Server supports server-to-server interactions. The requesting application has to prove its own identity to gain access to an API, and an end-user doesn’t have to be involved.
The client can request an access token using only its client credentials (or other supported means of authentication) when the client is requesting access to the protected resources under its control, or those of another resource owner that have been previously arranged with the authorization server.
The client makes a request to the token endpoint by adding the following parameters:
Parameter | Description |
---|---|
grant_type | (required) Value MUST be set to “client_credentials”. |
scope | (required) Required Scopes |
For example, the client makes the following HTTP request using transport-layer security (with extra line breaks for display purposes only):
POST /oauth2/token HTTP/1.1
Host: https://openstackid.org/
Authorization: Basic Base64-Encoded(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=write.endpoint.api
An example successful response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"123456",
"token_type":"Bearer",
"expires_in":3600
}