# Authentication Fervor uses [OAuth 2](https://oauth.net/2/) for authentication so that clients don't need to store user credentials. Basic steps for using OAuth 2 with Fervor: 1. Get the instance domain from the user. 2. Register your client with the Fervor API on that domain ([Client Registration](#client-registration)) to get the client ID and secret. 3. Navigate to the authorize endpoint to allow the user to log in ([Authorization Code Request](#authorization-code-request)) to generate the authorization code. 4. Request the access token from the server ([Access Token Request](#access-token-request)). See the [Example](#example) below for a concrete example of the Fervor authentication flow. **Notes**: Servers may implement token expiration and refreshing, so clients should be capable of handling either possibility. See [Refreshing Access Tokens](#refreshing-access-tokens) for details. Servers may implement password authentication for obtaining an access token, however, this should **only** be used for testing/in development. See [Password Authentication](#password-authentication) for details. ## Client Registration To register your client with the server, make a POST request to `/api/v1/register`. #### Parameters Parameters should be sent as `application/x-www-form-urlencoded` in the POST body. | Key | Description | Required | | -------------- | ---------------------------------------------------------------------- | -------- | | `client_name` | String. The name of your client. May be presented to the user. | Yes | | `website` | URL. The URL of your client or homepage. May be presented to the user. | No | | `redirect_uri` | URI. The URI the redirected to after a successful login. | Yes | The redirect URI must not include a fragment, and may include query parameters. The redirect URI may be the special `urn:ietf:wg:oauth:2.0:oob` string to indicate that server should show the authorization code on the web page, instead of performing a redirect. #### Response An object with the client ID and secret to be used when retrieving an authorization code. | Key | Description | Required | | --------------- | -------------------------- | -------- | | `client_id` | String. The client ID. | Yes | | `client_secret` | String. The client secret. | Yes | ## Authorization Code Request Now that you have a client ID and secret, the user needs to log in to the server to allow the client to access their account and a authorization code to be generated. Navigate to `/oauth/authorize` in a web browser (either a browser embedded in a native application, or the user's web browser itself). The following query parameters should be included: | Key | Description | Required | | --------------- | ------------------------------------------------------------------------------------------------------------------- | -------- | | `response_type` | String. Must be `code`. | Yes | | `client_id` | String. The client ID received from the previous step. | Yes | | `redirect_uri` | URI. The URI the user will be redirected to after a successful login. **Must** be the same as in the previous step. | Yes | | `state` | Any. Session state/ID may be included here. If provided, the redirect will include the same query parameter value. | No | The user will then be prompted to log in and approve your client. After this has happened, the user will be redirected (using a `302 Found` response with a `Location` header) back to the redirect URI you specified with the additional query parameter `code` containing the authorization code. If a `state` parameter was given to the request, the same value will be provided in the redirect's `state` query parameter. ## Access Token Request ### `POST /oauth/token` Uses the client ID and secret to get an authorization code and #### Parameters Parameters should be sent as `application/x-www-form-urlencoded` in the POST body. | Key | Description | Required | | -------------------- | ------------------------------------------------------------------------------- | -------- | | `grant_type` | String. The grant type being used. See below for supported options. | Yes | | `redirect_uri` | URI. **Must** be the same as in the previous steps. Only used for verification. | Yes | | `client_id` | String. The client ID received from the Client Registration step. | Yes | | `client_secret` | String. The client secret received from the Client Registration step. | Yes | ##### Supported Grant Types 1. `authorization_code`: Used to obtain an access token from an authorization code. The following parameters should also be included: - `authorization_code`: String. The authorization code received from the [Authorization Code Request](#authorization-code-request) step. 2. `refresh_token`: Used to refresh an existing access token that has expired. The following parameters should also be included: - `refresh_token`: String. The refresh token that was received from the previous Access Token response. 3. `password`: Used to obtain an access token from a users credentials. **Password grants should _never_ be used in production; they are available for development/testing purposes only.** The following parameters should also be included. - `username`: String. The user's username. - `password`: String. The user's password. #### Successful Response An object with information about the result of the access token request. **Note for server implementers:** This response must include the `Cache-Control: no-store` and `Pragma: no-cache` headers to ensure that the response is not cached by the client. | Key | Description | Required | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------- | | `access_token` | String. The access token issued by the server. | Yes | | `token_type` | String. The type of the issued token. Must be `bearer`. | Yes | | `expires_in` | Integer. The number of seconds the access token is valid for. If specified, `refresh_token` must also also be. | Recommended | | `refresh_token` | String. The token that may be used to obtain a new access token when this one expires. If specified, `expires_in` must also be. | Recommended | #### Unsuccessful Responses Returned if the request is unsuccessful. See below for HTTP response codes and error types. | Key | Description | Required | | ------------------- | ------------------------------------------------------------- | -------- | | `error` | String. The type of the error. See below for possible values. | Yes | | `error_description` | String. A more detailed description of the error. | Yes | ##### 400 `invalid_request` The request is missing parameters, has invalid values, or otherwise can't be processed. ##### 401 `invalid_client` Authentication failed to an invalid client ID. ##### 400 `invalid_grant` The given authorization code is invalid/expired or the `redirect_uri` did not match the originally specified. ##### 400 `unsupported_grant_type` The `grant_type` used is not supported. ## Access Token Usage All Fervor access tokens are Bearer tokens. To use them, include the `Authorization: Bearer ` header on all your requests (where `` is your access token). ## Refreshing Access Tokens Implementing access token expiration is optional, so clients must be able to handle either possibility. If expiration/refreshing is implemented, the Access Token Response (see above) must include the `expires_in` and `refresh_token` parameters. After an access token expires, the refresh token will be used to obtain a new one. To obtain a new token, the [Access Token Request](#access-token-request) should be performed with the `refresh_token` grant type and parameter. A new access token will be received, and the new refresh token should be stored for future use. ## Password Authentication Using password authentication is vastly less secure and defeats the purpose of OAuth. As such, it should **never** be used in production. Clients are **not** required to implement, however, they may do so for testing and development purposes. To obtain an access token from user credentials, the client must first be registered as usual (see [Client Registration](#client-registration)) and then the [Access Token Request](#access-token-request) may be made with the `password` grant type and the `username`/`password` parameters. ## Example This is an example of the complete authentication flow from beginning to end. ### Step 1: Get the server domain from the user For this example, we'll use `fervor.example.com` ### Step 2: Register your client with the server. For this example, we'll pretend we're building a native application which is already registered to handle the `fervorclient://` URL scheme. If you're building a web application, you'd use a normal URL for your application. We'll send the following request: ``` POST /api/v1/register Host: fervor.example.com Content-Type: application/x-www-form-urlencoded client_name=Example%20Client&redirect_uri=fervorclient://oauth ``` and get back the following response: ``` HTTP/1.1 200 OK Content-Type: application/json { "client_id": "rH58aObIri1OTCSw2q0L", "client_secret": "5LfDsOyrDSmq6f4EHe3v" } ``` ### Step 3: Prompt the User to Log In Next, we'll need to allow the user to log in to their account so that we can receive an authorization code. To do this, we'll open the following URL in a web view inside our imaginary app: ``` https://fervor.example.com/oauth/authorize?response_type=code&client_id=rH58aObIri1OTCSw2q0L&redirect_uri=fervorclient://oauth ``` Once the user logs in and agrees to allow our app to interact with their account, the web view will be redirected to the following URL containing our authorization code. ``` fervorclient://oauth?code=ypqBbDdsOXUeYJFnlbT0 ``` We can detect when we're redirected to `fervorclient://oauth` and close our web view, storing the authorization code from the `code` query parameter. ### Step 4: Exchange the Authorization Code for an Access Token Now that we've got an authorization code, we can obtain an access token that can be used to interact with the Fervor API. We'll make another request, this time to the token endpoint: ``` POST /oauth/token Host: fervor.example.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&redirect_uri=fervorclient://oauth&client_id=rH58aObIri1OTCSw2q0L&client_secret=5LfDsOyrDSmq6f4EHe3v&authorization_code=ypqBbDdsOXUeYJFnlbT0 ``` and we'll get back a response with an access token we can use: ``` HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "access_token": "Bsltr6EAUIiAKCtw3ieg", "token_type": "bearer", "expires_in": 3600, "refresh_token": "Tr6xsiZN3dFKygaZQNlb" } ``` We'll store the access token for use with API calls, and the refresh token for use in an hour when the current access token expires. ### Step 5: Making API Calls We can now use our access token to make API calls: ``` GET /api/v1/instance Host: fervor.example.com Authorization: Bearer Bsltr6EAUIiAKCtw3ieg ``` and we'll get back an Instance object. ### Step 6: Refreshing the Token After an hour has passed, our access token will have expired, so we'll need to generate a new one using the refresh token we received. We'll once again make a request to the token endpoint, this time with the `refresh_token` grant type: ``` POST /oauth/token Host: fervor.example.com Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&redirect_uri=fervorclient://oauth&client_id=rH58aObIri1OTCSw2q0L&client_secret=5LfDsOyrDSmq6f4EHe3v&refresh_token=Tr6xsiZN3dFKygaZQNlb ``` and we'll get back a new access token response: ``` HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "access_token": "PbBBXlPNONhxhdkG6gUu", "token_type": "bearer", "expires_in": 3600, "refresh_token": "DyEC8hLOazgwLS7cUbBb" } ```