Using Gandi’s OAuth2 Server

The OAuth2 server is available at https://id.gandi.net

Note: there is another OAuth2 service available at http://oauth2.gandi.net/ however this is used exclusively by Google Apps. These two services are very different and must not be confused with each other.

The OAuth2 authorization protocol is done in two steps, where we share secrets with one third party but not the other.

  • the first step is a request from the browser to the server
  • the second is a request from server to server.

Below is some information about the urls available on the id.gandi.net service:

/authorize or /{lang}/authorize

The purpose of this url is to ask a user for the authorization to access their resources via a third-party application (for applications developed by Gandi, this authorization is implicit and so we do not ask the user).

This will automaticaly redirect depending on the language of the browser. You can explicitely define a desired language using the “lang” parameter if you know it. We currently only support English, French, Spanish, Traditional Chinese, and Simplified Chinese.

These URLS must be followed by the following HTTP GET parameters:

client_id

  • Provided during the registration of the application
  • Identifies the client that makes the request for the user.

redirect_uri

  • Must be preset as “callback url”. You can add GET parameters and #anchors to it as they are preserves.
  • Note that “error”, “error_description”, “code”, and “state” are reserved parameters and will be removed or replaced to maintain the proper functioning of the protocole,

state

This is optional but highly recommended.

  • Will be added to your redirect_uri url. The client must keep the state in the user’s session before redirecting to the callback address.
  • The callback url must verify that the sessions’s state is identical to the state parameter returned via GET in order to allow the use of the redirection address.

scope (optional)

  • By default, the scope is predefined during the registration of the application.
  • The configurable scope allows restricting the predefined scope, though it can not expand it.
  • Any request for a permisssion outside the predefined scope will be considered as an error.

Once the authorization has been accepted or refused, the browser will be redirected to the redirect_uri url that is sent as a parameter, with the following parameters.

If successful:

  • code: An “authorization code” that must be sent from server to server.
  • state (optional - guaranteed if sent during the authentification request): The state sent via a GET parameter is resent to approve the browser for visiting the callback url.

In the event of an error:

  • error: The error code is defined here: https://tools.ietf.org/html/rfc6749#page-27
  • error_description: Additional information on the error, in English, and without any special characters, as outlined in the RFC.
  • state (optional): The state sent via a GET parameter is resent to approve the browser for visiting the callback url.

/token

This url is used to fabricate a couple of confidential tokens for the client application.

Neither the “access token” or the “refresh token” must be plainly exposed either in the application or outside the application. The tokens must be stored in a session. The sessions (cookies) must imperatively be encrypted. Gandi reserves the right to deactivate any application that does not respect this technical constraint.

This url is therefore an API that is only used server-to-server, with the application/x-www-form-urlencoded formated HTTP POST parameters as follows:

grant_type {authorization_code or refresh_token}

  • The first use is made with an authorization_code that consumes the preceeding /authorize reply code. The refresh_token is then used and consumes the refresh_token returned by the /token route itself.

client_id

  • Provided during the registration of the application.
  • This identifies the client that is making the authorization for the user.

client_secret

  • Provided during the registration of the application.
  • This identifies the client. The secret can not be shared by multiple clients.

token

  • If grant_type=refresh_token, it contains the refresh token to consume.
  • A refresh token can only be consumed once.

code

  • If grant_type=authorization_code, it contains the authorization code to consume.
  • An authorization code can only be consumed once.

When grant_type=authorization_code the RFC doest not plan on the client_secret being sent. Consequently, the client is not authenticated. See: https://tools.ietf.org/html/rfc6749#page-30

Instead, we send the initial callback url. id.gandi.net ignors the redirect_uti parameter for this request. It is not identified, and the redirection has already been performed on the legitimate url because it was predefined in advance.

The RFC does not therefore secure the delivery of the first access/refresh token. Gandi has taken the decision to give priority to security over the respect of the standard.

Incidentially google has also made this choice: https://developers.google.com/identity/protocols/OAuth2WebServer#handlingresponse

Github goes even farther: https://developer.github.com/v3/oauth/#github-redirects-back-to-your-site

This url returns a json document containing an access_token, a refresh_token, as well as a expires_in property that contains a TTL, in seconds, for the access token. The refresh_token never expires, and can only be consumed once via /token.

/tokeninfo

This url is a server-to-server API since it consumes an access token.

This is therfore the first oauth2 API to call. IT does not require any particular scope. IT returns the uuid of the client, (which never changes), the username of the user (this can be changed), the expires_in property, the remaining TTL in seconds of the access token in a field, as well as the scope of the token.

The email address of the user will be returned as well if the account:email scope has been predefined

GET /tokeninfo
https://tools.ietf.org/html/rfc6749#page-49
Authorization: bearer fgndfg-access-token-wefqz

Returns

{"username": "johnhsmith",
 "user_id": "9811c27a-cfd1-11e9-a423-00163ee24379",
 "expires_in": 3598,
 "scope": []}

or

{"username": "johnhsmith",
 "user_id": "9811c27a-cfd1-11e9-a423-00163ee24379",
 "expires_in": 3598,
 "scope": ["account:email"],
 "email": "johnhsmith@example.com"}