---
url: https://flat.io/developers/docs/api/authentication.md
---

# Flat API Authentication

The Flat Platform API uses [OAuth 2.0](https://oauth.net/2/) for authentication and authorization. If you never used OAuth2 before, we advise you to read this [great introduction](https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2). Our API supports the **Authorization Code** grant (with [PKCE](#public-clients-native-and-mobile-apps) for native and mobile apps) and the **Implicit** grant. To simplify the usage of our API for your own account, you can quickly create access tokens in your Flat account (aka. "Personal Access Tokens").

## How to quickly getting started

1. [Create an app](https://flat.io/developers/apps) for your script or project.
2. **Try the API in 5 minutes** with [a Personal Access Token for your Flat account](#personal-access-tokens).
3. If you plan to make the app available for other people, [create OAuth2 credentials](#oauth2) for it.

## Personal Access Tokens

Personal Access Tokens function like OAuth access tokens for your own account. You can generate them from your account in a few seconds:

1. [Create an app](https://flat.io/developers/apps) for your script or project
2. On the left menu, click on "**REST API > Personal tokens**"
3. Choose a name and the authorization scopes for your first token.

That's all, you can directly use our API with this token by setting it in the `Authorization` headers of your requests:

```http
Authorization: Bearer my-api-personal-access-token
```

Here is an example with cURL:

```bash
curl -H 'Authorization: Bearer <my_api_personal_access_token>' https://api.flat.io/v2/me
```

## OAuth2

Create OAuth2 credentials from your app in the [developer dashboard](https://flat.io/developers/apps), under "**REST API > OAuth2 credentials**". Each credential has a callback URL, a set of scopes, and a client type that cannot be changed after creation:

* **Confidential client** (web app with a server): gets a client secret, shown only once at creation. Keep it on your server.
* **Public client** (native, mobile or desktop app): gets no secret and must use [PKCE](#public-clients-native-and-mobile-apps). Use it for any app that runs on the user's device, where a secret could be extracted.

Some scopes need a review by Flat before your OAuth2 credentials can request them (see [Scopes](#scopes)). Personal access tokens are not concerned. For those, email <developers@flat.io> with your app and what you need the scopes for.

Here is the main information for our OAuth2 API, you can learn more about the scopes and flows in the paragraphs below.

* Authorization URL: `https://flat.io/auth/oauth`
* Token URL: `https://api.flat.io/oauth/access_token`
* Invalidation URL: `https://api.flat.io/oauth/invalidate_token`
* [List of scopes](#scopes)

## Scopes

Request the scopes your app needs in the `scope` parameter of the [authorization page](#authorization-page). **Users see** is the sentence shown to them on the consent page, in their language. Scopes marked  need Flat's approval before your OAuth2 credentials can request them: email <developers@flat.io>. [Personal access tokens](#personal-access-tokens) are not reviewed: they can carry any of these scopes for your own account, limited to what your account itself can do.

### Account

| Scope | What it allows | Users see |
|:--|:--|:--|
| `account.public_profile` | Provides access to the person's basic public profile. Education profiles may be anonymized with this scope; request the scope `account.education_profile` to access a basic education account profile. | “Access your public profile” |
| `account.email` | Provides access to the person's email. | “Access your account email address” |
| `account.education_profile` | Provides access to the person's basic education profile and public organization information. | “Access your education profile” |

### Scores

| Scope | What it allows | Users see |
|:--|:--|:--|
| `scores.readonly` | Allows read-only access to all of a user's scores. You won't need this scope to read public scores. | “View all your music scores” |
| `scores.social` | Allows posting comments and liking scores. | “Comment on and like music scores with your account” |
| `scores` | Full, permissive scope to access all of a user's scores. | “View and manage your music scores (including updating and removing them)” |

### Collections

| Scope | What it allows | Users see |
|:--|:--|:--|
| `collections.readonly` | Allows read-only access to a user's collections. | “View your collections” |
| `collections.add_scores` | Allows adding scores to a user's collections. | “Add new scores to your collections” |
| `collections` | Full, permissive scope to access all of a user's collections. | “View and manage your collections (including removing them)” |

### Notifications

| Scope | What it allows | Users see |
|:--|:--|:--|
| `notifications.readonly` | Read-only access to a user's notifications. | “View your notifications” |

### Flat for Education

| Scope | What it allows | Users see |
|:--|:--|:--|
| `edu.resources` | Read-write access to the resource library. | “View and manage your Resource Library” |
| `edu.resources.readonly` | Read-only access to the resource library. | “View your Resource Library” |
| `edu.classes` | Full, permissive scope to manage the classes. | “View and manage your classes” |
| `edu.classes.readonly` | Read-only access to the classes. | “View your classes” |
| `edu.assignments` | Read-write access to the assignments and submissions. | “View and manage your assignments” |
| `edu.assignments.readonly` | Read-only access to the assignments and submissions. | “View your assignments” |

### Flat for Education: organization admin

| Scope | What it allows | Users see |
|:--|:--|:--|
| `edu.admin`  | Full, permissive scope to administer an organization. | “Complete admin access to your organization” |
| `edu.admin.lti`  | Access and manage the LTI Credentials for an organization. | “View and manage your LTI integrations and credentials” |
| `edu.admin.lti.readonly`  | Read-only access to the LTI Credentials of an organization. | “View your LTI integrations and credentials” |
| `edu.admin.users`  | Access and manage the users and invitations of the organization. | “View and manage your users' accounts” |
| `edu.admin.users.readonly`  | Read-only access to the users and invitations of the organization. | “View your users' accounts” |

### Billing

| Scope | What it allows | Users see |
|:--|:--|:--|
| `billing`  | Full access to the billing API endpoints. | “View and manage your billing details, subscriptions and invoices” |
| `billing.readonly`  | Read-only access to the billing API endpoints. | “View your billing details, subscriptions and invoices” |

### Export tasks

| Scope | What it allows | Users see |
|:--|:--|:--|
| `tasks.readonly` | Read-only access to export tasks created by this account. | “Read-only access to export tasks created by this account” |

### Optical Music Recognition

| Scope | What it allows | Users see |
|:--|:--|:--|
| `omr` | Run Optical Music Recognition jobs and download their results. The `library` output additionally requires the `scores` scope. | “Convert your sheet music images and PDFs into scores using your AI credits” |
| `omr.readonly` | Read-only access to Optical Music Recognition jobs and their results. | “View your sheet music imports and their results” |

These tables are generated from the API on every docs deploy. Read the list at runtime rather than hard-coding it: new scopes may be added. Send `x-flat-locale` to get the labels in another language:

```bash
curl -H 'x-flat-locale: fr' https://api.flat.io/v2/apps/oauth2/scopes
```

## Authorization Page

Both **Authorization Code** and **Implicit** OAuth2 grants start with our authorization page. Our Authorization page (`https://flat.io/auth/oauth`) supports all the standard parameters from the **Authorization Code** grant ([RFC6749/4.1](https://tools.ietf.org/html/rfc6749#section-4.1)) and the **Implicit** grant ([RFC6749/4.2](https://tools.ietf.org/html/rfc6749#section-4.2)).

The first step is to build an authorization link where you can redirect your user. Here is a simple example:

```text
https://flat.io/auth/oauth?client_id=<client_id>&response_type=(code|token)&state=<state>&scope=account.public_profile+scores&redirect_uri=<redirect_uri>
```

You can find below the different parameters available, including non-standard and optional parameters. All of them can be passed as query string when redirecting the end-user to the authorization page.

Property name  | Required | Values and Description
\---------------|----------|-----------------------
`client_id`    | Required | The client key of your OAuth2 credential
`response_type`| Required | We support `code` (**Authorization Code** grant, [RFC6749/4.1.1](https://tools.ietf.org/html/rfc6749#section-4.1.1)) and `token` (**Implicit**, [RFC6749/4.2.1](https://tools.ietf.org/html/rfc6749#section-4.2.1)). Use the Authorization Code grant for server-side usage, and the Authorization Code grant with PKCE for native and mobile apps. Public clients cannot use the Implicit grant.
`scope`        | Required | You must provide a list of scopes listed above and granted for your app, separated with a space.
`redirect_uri` | Required | Determines where the response is sent. The value of this parameter must exactly match the callback URL of your credential. For a public client with an `http://localhost` or `http://127.0.0.1` callback URL, any port is accepted.
`state`        | Optional | An opaque string that is round-tripped in the protocol; that is to say, it is returned as a URI parameter in the Authorization Code grant, and in the URI #fragment in the Implicit grant.
`access_type`  | Optional (available for the Authorization Code grant) | The acceptable values are `online` and `offline`. When specifying `offline`, the API will return a refresh token during the access token exchange (see [Refreshing an access token](#refreshing-an-access-token)).
`code_challenge` | Required for public clients, optional for confidential ones | PKCE code challenge ([RFC7636](https://tools.ietf.org/html/rfc7636)): `BASE64URL(SHA256(code_verifier))`, without padding. See [Public clients](#public-clients-native-and-mobile-apps).
`code_challenge_method` | Optional | Only `S256` is supported, and it is the default. `plain` is refused.

When redirecting your users to this authorization page, they will see a page that looks like the one below, where they can grant your app to access and use their account:

![Flat OAuth2 Authorization Page](/img/api-authz-page.png)

## Authorization Code grant

Here is a typical flow of an **Authorization Code grant**. We advise you to use this grant for using our API in **server-side**.

1. You redirected a visitor/user to our [authorization page](#authorization-page) by specifying `response_type=code`, your `client_id` and a `redirect_uri`.
2. This user granted your app on our authorization Page.
3. Flat redirects your user back to your website at the `redirect_uri` you specified. You will receive a `code` query string with an Authorization Code that you can exchange for an access token. This URL will also include a previous `state` you specified in the authorization page URL. (e.g. `https://my-website.example.com/callback?code=<authz-code>&state=<state>`)
4. To exchange this Authorization Code, use our Token API Endpoint, `https://api.flat.io/oauth/access_token` ([RFC6749/4.1.3](https://tools.ietf.org/html/rfc6749#section-4.1.3)).

Here is an exchange request example (server-side):

```bash
curl -i -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
 -d grant_type=authorization_code \
 -d code=<authz-code> \
 -d client_id=<client_id> \
 -d client_secret=<client_secret> \
 -d redirect_uri=<redirect_uri> \
 https://api.flat.io/oauth/access_token
```

And a response for this request:

```json
{
  "type": "access",
  "token_type": "bearer",
  "access_token": "<access-token>",
  "issued_at": 1492542537,
  "expires_in": 86400,
  "app": "<your-app-id>",
  "appStatus": "trusted",
  "user": "<user-id>",
  "scope": "account.public_profile scores"
}
```

The access token is now ready to use, here is an example with cURL:

```bash
curl -H 'Authorization: Bearer <access-token>' https://api.flat.io/v2/me
```

## Public clients (native and mobile apps)

An app running on the user's device (iOS, Android, desktop) cannot keep a secret, so its credential is a **public client**: no secret is issued, and the Authorization Code grant must use PKCE ([RFC7636](https://tools.ietf.org/html/rfc7636)). PKCE binds the authorization code to the app that asked for it: only the holder of the `code_verifier` can exchange it.

1. Generate a random `code_verifier` (43 to 128 characters from `A-Z`, `a-z`, `0-9`, `-`, `.`, `_`, `~`), and keep it in memory for this sign-in.
2. Compute the `code_challenge`: the SHA-256 hash of the verifier, encoded in base64url without padding.
3. Open our [authorization page](#authorization-page) in the system browser (e.g. `ASWebAuthenticationSession` on iOS, Custom Tabs on Android) with `response_type=code`, your `client_id`, `redirect_uri`, `code_challenge` and `code_challenge_method=S256`. Add `access_type=offline` to get a refresh token.
4. Flat redirects to your `redirect_uri` with a `code`. Exchange it at the Token API Endpoint with the `code_verifier` and no `client_secret`.

Here is how to generate a verifier and its challenge in a shell:

```bash
CODE_VERIFIER=$(openssl rand -base64 64 | tr -d '\n=' | tr '/+' '_-' | cut -c1-64)
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr -d '\n=' | tr '/+' '_-')
```

And the exchange request:

```bash
curl -i -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
 -d grant_type=authorization_code \
 -d code=<authz-code> \
 -d client_id=<client_id> \
 -d code_verifier=<code_verifier> \
 -d redirect_uri=<redirect_uri> \
 https://api.flat.io/oauth/access_token
```

The callback URL of a public client can be:

* A custom scheme handled by your app, such as `com.example.app:/oauth`. A reverse-domain scheme based on a domain you own is recommended ([RFC8252](https://tools.ietf.org/html/rfc8252#section-7.1)). Schemes handled by the browser or the system (`javascript:`, `data:`, `file:`, `mailto:`, …) are refused.
* An `https` URL, for example a universal link or app link.
* `http://localhost` or `http://127.0.0.1`, for desktop apps listening on a local port. Any port is accepted at authorization.

Since another app could claim the same custom scheme or local port, users see the consent page on every sign-in when the callback URL is not `https`, even if they authorized your app before.

## Refreshing an access token

Access tokens expire after 24 hours (`expires_in`, in seconds). When the authorization was requested with `access_type=offline`, the token response also contains a `refresh_token` that you can exchange for a new access token ([RFC6749/6](https://tools.ietf.org/html/rfc6749#section-6)):

```bash
curl -i -X POST -H 'Content-Type: application/x-www-form-urlencoded' \
 -d grant_type=refresh_token \
 -d refresh_token=<refresh-token> \
 -d client_id=<client_id> \
 -d client_secret=<client_secret> \
 https://api.flat.io/oauth/access_token
```

Public clients send their `client_id` without a `client_secret`.

Each refresh returns a new `refresh_token` and invalidates the one you sent, so always store the latest one. Refresh tokens of confidential clients don't expire. Refresh tokens of public clients expire after 30 days (`refresh_token_expires_in`, in seconds); after that, the user signs in again.

## Implicit grant

Here is a typical flow of an **Implicit grant**. This grant is available to confidential clients only. For an app running on the user's device, prefer the [Authorization Code grant with PKCE](#public-clients-native-and-mobile-apps). We main difference with the Authorization Code grant is that you don't need to exchange a code, you directly get the access token in the URI Hash.

1. You redirected a visitor/user to our [authorization page](#authorization-page) by specifying `response_type=token`, your `client_id`, and a `redirect_uri`.
2. This user granted your app on our authorization Page.
3. Flat redirects your user back to your website at the `redirect_uri` you specified. You will receive the access token in the URI Hash (see example below).

```text
https://my-website.example.com/callback#scope=account.public_profile&expires_in=86400&access_token=<access-token>
```

The access token is now ready to use, here is an example with the JavaScript Fetch API:

```javascript
fetch('https://api.flat.io/v2/me', {
  headers: {
    'Authorization': 'Bearer ' + ACCESS_TOKEN
  }
})
.then(function (response) {
  return response.json();
})
.then(function (me) {
  console.log(me);
});
```

## Tokens revocation

This OAuth2 API supports token revocation ([RFC 7009](http://tools.ietf.org/html/rfc7009)) at the following endpoint: `https://api.flat.io/oauth/invalidate_token`.
