---
updatedAt: 2025-09-25T19:45:34.000Z
agentTools:
  projectIndex: https://developers.shine.fr/llms.txt
---

# OAuth2

OAuth2 enables third-party applications to authenticate users and get data from the Shine API.

> 👍 If you don't have any credentials yet, the first thing to get started is to fill this [form](https://tally.so/r/3qAy69). We will send your `client_id` and `client_secret` once your request is accepted.

# URLs

Base authorization URL: **[api.shine.fr/v2/authentication/oauth2/authorize](https://api.shine.fr/v2/authentication/oauth2/authorize)**\
Token URL: **[api.shine.fr/v2/authentication/oauth2/token](https://api.shine.fr/v2/authentication/oauth2/token)**\
Revocation URL: **[api.shine.fr/v2/authentication/token/revoke](https://api.shine.fr/v2/authentication/oauth2/token/revoke)**

# Security considerations

To prevent security vulnerabilities like [Cross Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery), CSRF, or [Clickjacking](https://en.wikipedia.org/wiki/Clickjacking) we strongly recommend you to use an additional **`state`** parameter that should be a value that binds the user's request to their authenticated state. For example, `state` could be a hash of the user's session cookie, or something else that can be linked to the user's session.

On the client side, before beginning the authorization flow, generate a **`state`** that is unique to that user's request. The value should be stored somewhere only accessible to the client and the user ([same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy)). When the user is redirected, the **`state`** parameter is returned. The client validates the request by checking that the **`state`** returned matches the stored value. If they match, it is a valid authorization request. If they do not match, it's possible that someone intercepted the request and the request should be denied.

> ❗️ While Shine does not require the use of the **`state`** parameter, we highly recommend that you implement it for the security of your own applications and users' data.

> 📘 For details on how to implement OAuth2 please see [RFC 6749](https://tools.ietf.org/html/rfc6749) or any online articles considering your app language.

# Authorization Flow (Code Grant)

This is the grant type most often associated with OAuth: Code Grant allows the authorization server to act as an intermediary between the client (your server) and the resource owner (the user), so the resource owner's credentials are never shared directly with the client. We decided to only support the Code Grant flow for improved security.

<Image title="flow.jpg" alt={2557} width="80%" src="https://files.readme.io/0071a4f-flow.jpg" />

# Step 1 - Ask users to authorize your app

To connect with shine, your web or mobile app should redirect users to the following URL:

**`https://api.shine.fr/v2/authentication/oauth2/authorize`**

With the following GET parameters values:

**`client_id:`** Your application's client\_id\
**`scope:`** A list of available scopes separated by encoded spaces (%20)\
**`redirect_uri:`** The redirection URL with which you registered your application\
**`state:`** Unique string to be passed back upon completion (see Security Considerations)

## Authorization URL Example

```http request
https://api.shine.fr/v2/authentication/oauth2/authorize?client_id=127332580432496061&scope=openid%20bank:transfers:write&state=QS9DkxQS1ZEDSQKD&redirect_uri=https%3A%2F%2Fyou.com
```

The user will be prompted to authorize your application for the requested scopes. On acceptance, they will be redirected to your **`redirect_uri`**.

# Step 2 - Redirect users to your server with a verification code

If the user authorized your app, we will redirect him back to your **`redirect_uri`** with a temporary code in a **`code`** GET parameter, as well as a **`state`** parameter if previously sent to the authorization endpoint. As specified in the "Security Considerations", you should check the state with the one you stored. If the states don't match, the request may be malicious and you should stop the process.

## Redirect URL example

```http request
https://yourapp.com/?code=PxAvx90lLFc8gLNaaLoj9l7Ku7bEEcee&state=QS9DkxQS1ZEDSQKD
```

# Step 3 - Exchanging a verification code for an access token

You can now exchange the verification code to get an access token by making a POST request to the token URL **`https://api.shine.fr/v2/authentication/oauth2/token`** with the following parameters passed in the request's body:

**`client_id`** - your application's client id\
**`client_secret`** - your application's client secret\
**`grant_type`** - must be set to authorization\_code\
**`code`** - the code from the querystring\
**`redirect_uri`** - your redirect\_uri

## Access token example

```javascript
import axios from 'axios';

const API_OAUTH_ENDPOINT = 'https://api.shine.fr/v2/authentication/oauth2';
const CLIENT_ID = '127332580432496061';
const CLIENT_SECRET = 'Losq!21ksqç012kkxlApOOix198x1';
const REDIRECT_URI = 'https://yourapp.com';

const requestAccessToken = (code) => {
  const body = {
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: REDIRECT_URI,
  };
  const headers = {
    'Content-Type': 'application/json',
  };
  return axios.post(`${API_OAUTH_ENDPOINT}/token`, body, { headers });
};
```

In response, you will receive:

```json
{
  "access_token": "XXXXXXXXXX8AOixpaiId872XXXXXXXX",
  "token_type": "Bearer",
  "id_token": "XXXXXXXXXXQA9SJxiQ921XXXXXXXX",
  // only if openid is required in scope
  "expires_in": 604800,
  "refresh_token": "XXXXXXXXXX9819x74590poXXXXXXXX",
  "scope": "openid bank:transfers.write",
  "metadata": {
    "companyProfileId": "XXXXXXXXXX3472g48591qeXXXXXXXX",
    "companyUserId": "XXXXXXXXXX8135j72946fsXXXXXXXX",
    "uid": "XXXXXXXXXX6239k48257moXXXXXXXX"
  }
}
```

`metadata` field contains the user's `uid`, `companyProfileId` and `companyUserId`.\
You might need these values for subsequent requests.

With the users's access token you can make certain requests to the API on their behalf, depending on the scopes you requested.

**`expires_in`** represents how long until the returned access token expires, in seconds. You will need to anticipate the token expiration and refresh it if needed. To refresh, you will need to make another POST request to the token URL **`https://api.shine.fr/v2/authentication/oauth2/token`**\
with the following parameters passed in the request's body:

**`client_id`** - your application's client id\
**`client_secret`** - your application's client secret\
**`grant_type`** - must be set to **`refresh_token refresh_token`** - the user's refresh token\
**`redirect_uri`** - your **`redirect_uri`**

## Refresh Token Exchange Example

```javascript
import axios from 'axios';

const API_OAUTH_ENDPOINT = 'https://api.shine.fr/v2/authentication/oauth2';
const CLIENT_ID = '127332580432496061';
const CLIENT_SECRET = 'Losq!21ksqç012kkxlApOOix198x1';
const REDIRECT_URI = 'https://yourapp.com';

const refreshToken = (refreshToken) => {
  const body = {
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    redirect_uri: REDIRECT_URI,
    grant_type: 'refresh_token',
    refresh_token: refreshToken,
  };
  const headers = {
    'Content-Type': 'application/json',
  };
  return axios.post(`${API_OAUTH_ENDPOINT}/token`, body, { headers });
};
```

# ID Token

As specified in the Open Id Specification, you can require an **`id_token`** if you ask for the "openid" scope. **You can rely on this token to create accounts and authenticate users without asking for password like with Google or Facebook Connect.**

The **`id_token`** is a JWT signed using JSON Web Key Set (JWKS) that contains user profile informations, in the form of claims that you need to decode. How to precisely decode and validate a JWT is out of this documentation scope as it depends on your language and backend implementation. You can find more informations on [jwt.io](https://jwt.io). We strongly recommend to validate **`id_token`** as it can be intercepted or altered by third-parties. We use RS256 and JWKS to sign our tokens and you can get the public JWKS key on **`https://api.shine.fr/v2/authentication/oauth2/.well-known/jwks.json`**

to verify the JWT signature.

Please note that our JWKS key can be rotated.

You should also validate the claims once decoded:

**`exp`**: timestamp, must be greater than the current timestamp.\
**`iss`**: token issuer, must be <https://accounts.shine.fr>

## ID Token Content

```json
{
    iss: 'https://accounts.shine.fr',
    aud: your client_id,
    sub: string, shine uniq user id,
    exp: timestamp, token expire at,
    iat: timestamp, token issued at,
    // if "email" scope asked
    email: user email,
    email_verified: true or false,
    // if "phone" scope asked
    phone: '+336808080',
    // if "profile" scope asked
    name: user full name,
    given_name: user first name,
    family_name: user last name,
    birthdate: ISO 8601:2004, YYYY-MM-DD format,
    gender: male or female,
    picture: url of user picture,
    locale: user locale, represented as BCP47 tag (fr-FR, en-US...),
    updated_at: last user profile update timestamp,
    zone_info: string representing user time zone (Europe/Paris, America/Los_Angeles...).
}
```

# Request Denied

If the user do not allow your request, we will redirect him back to your **`redirect_uri`** with an error parameter as follow:\
**`https://you.com?error=access_denied&state=QS9DkxQS1ZEDSQKD`**

# Using AccessToken

To communicate with our API, you need to pass your access tokens, also known as bearer tokens, in the HTTP **`Authorization`** header as follow:

```http request
GET https://api.shine.fr/v2/bank/accounts
Authorization: Bearer XXXXX9E38Sksq29XXXXXX
```

# Revoking Tokens

If you or the user want to remove your app access, or change the requested scopes, you need to revoke the last refresh token using a POST request to the revoke token URL **`https://api.shine.fr/v2/authentication/oauth2/token/revoke`**

with the following parameters in the request's body:\
**`client_id`** - your application's client id\
**`client_secret`** - your application's client secret\
**`token`** - the **`refresh_token`** you want to revoke

## Revoking Token Example

```javascript
import axios from 'axios';

const API_OAUTH_ENDPOINT = 'https://api.shine.fr/v2/authentication/oauth2';
const CLIENT_ID = '127332580432496061';
const CLIENT_SECRET = 'Losq!21ksqç012kkxlApOOix198x1';

const revokeToken = (refreshToken) => {
  const body = {
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    token: refreshToken,
  };
  const headers = {
    'Content-Type': 'application/json',
  };
  return axios.post(`${API_OAUTH_ENDPOINT}/token/revoke`, body, { headers });
};
```

Revoking the refresh token will also revoke the access token. If you want to re-authenticate, you will need to start over the oauth2 flow to get new tokens.