How to Add a Custom OAuth2/OpenID Connect Provider to Strapi v4
Tags: strapi, oauth2, openid
Published: 2023-03-21 18:48:40

In this article, we will cover the required steps to add a custom OAuth2/OpenID Connect provider to Strapi 4.

First things first, what are OAuth2 and OpenID Connect?
OAuth2 handles authorization whereas OpenID Connect handles authentication. What’s the difference you may ask, well, OAuth2 is built to manage authorization access to APIs with scopes, and OpenID Connect is built on top of OAuth2 to manage authentication of users.
Strapi actually relies on OpenID Connect protocol to retrieve user info and create the internal Strapi user upon provider account connection.
If you want more details on what are those and the differences, I can only recommend the [**OAuth2 and OpenID Connect: The Professional Guide**](https://auth0.com/resources/ebooks/oauth-openid-connect-professional-guide) ebook by the guys behind Auth0 by Okta.

## Prerequisites

Before you can jump into this content, you need to have a basic understanding of the following.

1. Basic knowledge of JavaScript
2. A [Node.js](https://nodejs.org/en/) ready environment
3. Basic understanding of Strapi - [get started here](https://strapi.io/documentation/developer-docs/latest/getting-started/introduction.html)
## What is Strapi

Strapi is an open-source headless CMS based on Node.js that is used to develop and manage content using a Restful API and/or GraphQL.

With Strapi, we can scaffold our API faster and consume the content via APIs using any HTTP client or GraphQL enabled frontend.

## Scaffolding a Strapi project

To scaffold a new Strapi project is very simple and works precisely as installing a new frontend framework.

We are going to start by running the following commands and testing them out in our default browser.

``` bash
    npx create-strapi-app strapi-api --quickstart
    # OR
    yarn create strapi-app strapi-api --quick start
```

The command above will scaffold a new strapi project in the directory you specified.

Next, run `yarn build` to build your app and `yarn develop` to run the new project if it doesn't start automatically.

The last command will open a new tab with a page to register your new admin of the system. Go ahead and fill out the form and click on the submit button to create a new Admin.

# Patch Package
## What is it?

`patch-package` lets app authors instantly make and keep fixes to npm dependencies. It's a vital band-aid for those of us living on the bleeding edge.
Head over to its [GitHub repo](https://github.com/ds300/patch-package) if you want to know more.

## Why do we need it?

Well, Strapi manages OAuth2/OpenID Connect through a dependency, Grant. It then uses Purest to make some API calls to retrieve User information.
In order to have our OAuth2/OpenID Connect Provider to work with Strapi, we then have 2 options:

1. Get those dependencies to add our Provider (good luck with that if it is not something mainstream) and then have Strapi to use them
2. Patch those dependencies and add our own

I guess you figured we will go with the second option ;)

## Set it up in your project

Simply follow its [setup instructions](https://github.com/ds300/patch-package#set-up)

# Grant
## What is it?

Grant is an OAuth2/OpenID Connect proxy for Node.js with 200+ preconfigured providers.
More information in its [GitHub repo](https://github.com/simov/grant)

## Which changes are needed?

First, we need to check if the provider you want to use already exists in grant in the [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) file

1. It’s already there
    1. No patch required, you’re good to proceed to the next package
2. It’s not listed
    1. That’s the case in which we need to patch it
## Prepare the changes
- Add the OAuth2/OpenId Connect provider to the `node_modules/grant/config/oauth.json` file

``` json
      "trackmania": {
        "authorize_url": "https://api.trackmania.com/oauth/authorize",
        "access_url": "https://api.trackmania.com/api/access_token",
        "oauth": 2,
        "scope_delimiter": " "
      }
```

- Add the OAuth2/OpenId Connect provider to the `node_modules/grant/config/profile.json` file

``` json
      "trackmania": {
        "profile_url": "https://api.trackmania.com/api/user"
      }
```

## Make it a patch

Execute the following command

``` bash
    npm patch-package grant
    # OR
    yarn patch-package grant
```

This will create the `patches/grant+VERSION.patch` file where VERSION is the one you have currently installed

# Purest
## What is it?

Purest is a REST API client library with embeded providers, think of it as an axios with preconfigured base urls and endpoints for each provider.
More information on its [GitHub repo](https://github.com/simov/purest)

## Which changes are needed?

Same first step than Grant: Is your provider already listed in Purest?

1. Yep!
    1. No patch required, you’re good to proceed to the next package
2. Nope
    1. Let’s patch it!
## Prepare the changes
- Add the OAuth2/OpenID Connect provider to the `node_modules/purest/config/providers.json` file

``` json
      "trackmania": {
        "default": {
          "origin": "https://api.trackmania.com",
          "path": "api/{path}",
          "headers": {
            "authorization": "Bearer {auth}"
          }
        },
        "oauth": {
          "origin": "https://api.trackmania.com",
          "path": "oauth/{path}"
        }
```

## Make it a patch

Execute the following command

``` bash
    npm patch-package purest
    # OR
    yarn patch-package purest
```

This will create the `patches/purest+VERSION.patch` file where VERSION is the one you have currently installed

# Strapi Plugin Users Permissions
## What is it?

This is the Strapi’s internal way of handling Users and Permissions, in which the supported OAuth2/OpenID Connect providers are implemented

## Which changes are needed?

We will need to edit multiple files for the provider to work, just follow along ;)

## Prepare the changes
- Add grant cofig in `node_modules/@strapi/plugin-users-permissions/server/bootstrap/grant-config.js` file

``` json
      trackmania: {
        enabled: true,
        icon: 'trackmania',
        key: '',
        secret: '',
        basicHeader: '',
        openPlanetSecret: '',
        callback: `${baseURL}/trackmania/callback`,
        scope:[]
      }
```


- Add implementation in `node_modules/@strapi/plugin-users-permissions/server/services/providers-registry.js` file

``` javascript
      async trackmania({ accessToken }) {
        const trackmania = purest({ provider: 'trackmania' });
        const { body: userBody } = await trackmania.get('user').auth(accessToken).request();
    
        // The userBody may differ from provider to provider, refer to the provider documentation for details
        return {
          username: userBody.displayName,
          email: userBody.email
        };
      }
```


## Make it a patch

Execute the following command

``` bash
    npm patch-package @strapi/plugin-users-permissions
    # OR
    yarn patch-package @strapi/plugin-users-permissions
```

This will create the `patches/@strapi/plugin-users-permissions+VERSION.patch` file where VERSION is the one you have currently installed

# Conclusion

This article demonstrated how to add a custom Login Provider to Strapi 4.
[Here is a demo repo](https://github.com/christopheCVB/strapi-custom-oauth) where you’ll find an example implemetation.

Let me know if you have any question/suggestion, I’d love to hear your feedback ;)