Using Gandi’s OAuth2 Server

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

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.

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, Japanese, German, 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 preserved.
  • Note that error, error_description, code, and state are reserved parameters and will be removed or replaced to maintain the proper functioning of the protocol,

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 formatted 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.

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 does 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 https://id.gandi.net ignores the redirect_uri 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 an expires_in property that contains a TTL, in seconds, for the access token. The refresh_token never expires.

/tokeninfo

See https://tools.ietf.org/html/rfc6749#page-49.

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 (user_id, which never changes) of the authenticated user, the username of the user (which can be changed), the expires_in property (the remaining TTL in seconds of the access token), as well as the scope of the token.

GET /tokeninfo
Authorization: bearer fgndfg-access-token-wefqz

Returns

{"user_id": "9811c27a-cfd1-11e9-a423-00163ee24379",
 "expires_in": 3598,
}

or

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

If you want to get more information on the user account, please refer to the following page for instructions: https://api.gandi.net/docs/organization/#v5-organization-user-info

Note that doing so requires the ‘organization:view’ scope).