diff --git a/docs/v3.x/plugins/users-permissions.md b/docs/v3.x/plugins/users-permissions.md
index 6f6924959e..2bf13f0eaf 100644
--- a/docs/v3.x/plugins/users-permissions.md
+++ b/docs/v3.x/plugins/users-permissions.md
@@ -493,6 +493,40 @@ The use of `ngrok` is not needed.
:::
+::: tab LinkedIn
+
+#### Using ngrok
+
+LinkedIn accepts the `localhost` urls.
+The use of `ngrok` is not needed.
+
+#### LinkedIn configuration
+
+- Visit the Apps list page
[https://www.linkedin.com/developers/apps](https://www.linkedin.com/developers/apps)
+- Click on **Create app** button
+- Fill the information:
+ - **App name**: Strapi auth
+ - **LinkedIn Page**: Enter a LinkedIn page name to associate with the app or click **Create a new LinkedIn Page** to create a new one
+ - **App Logo**: Upload a square image that is at least 100x100 pixels.
+- Click on the **Create app** to create the app
+- On the app page click on **Auth** tab
+- Fill the information:
+ - **Authorized redirect URL**: `http://localhost:1337/connect/linkedin/callback`
+- On the app page click on **Products** tab.
+- Select `Sign In with LinkedIn` from the product list to enable it.
+
+#### Strapi configuration
+
+- Visit the User Permissions provider settings page
[http://localhost:1337/admin/plugins/users-permissions/providers](http://localhost:1337/admin/plugins/users-permissions/providers)
+- Click on the **LinkedIn** provider
+- Fill the information:
+ - **Enable**: `ON`
+ - **Client ID**: 84witsxk641rlv
+ - **Client Secret**: HdXO7a7mkrU5a6WN
+ - **The redirect URL to your front-end app**: `http://localhost:3000/connect/linkedin/redirect`
+
+:::
+
::::
Your configuration is done.
diff --git a/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js b/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js
index be16ee70bd..41dedb3aa8 100644
--- a/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js
+++ b/packages/strapi-plugin-users-permissions/config/functions/bootstrap.js
@@ -94,6 +94,14 @@ module.exports = async () => {
callback: `${strapi.config.server.url}/auth/twitch/callback`,
scope: ['user:read:email'],
},
+ linkedin: {
+ enabled: false,
+ icon: 'linkedin',
+ key: '',
+ secret: '',
+ callback: `${strapi.config.server.url}/auth/linkedin/callback`,
+ scope: ['r_liteprofile', 'r_emailaddress'],
+ },
};
const prevGrantConfig = (await pluginStore.get({ key: 'grant' })) || {};
// store grant auth config to db
diff --git a/packages/strapi-plugin-users-permissions/services/Providers.js b/packages/strapi-plugin-users-permissions/services/Providers.js
index ab7504be6a..867c0efd9c 100644
--- a/packages/strapi-plugin-users-permissions/services/Providers.js
+++ b/packages/strapi-plugin-users-permissions/services/Providers.js
@@ -386,6 +386,69 @@ const getProfile = async (provider, query, callback) => {
});
break;
}
+ case 'linkedin': {
+ const linkedIn = purest({
+ provider: 'linkedin',
+ config: {
+ linkedin: {
+ 'https://api.linkedin.com': {
+ __domain: {
+ auth: [{ auth: { bearer: '[0]' } }],
+ },
+ '[version]/{endpoint}': {
+ __path: {
+ alias: '__default',
+ version: 'v2',
+ },
+ },
+ },
+ },
+ },
+ });
+ try {
+ const getDetailsRequest = () => {
+ return new Promise((resolve, reject) => {
+ linkedIn
+ .query()
+ .get('me')
+ .auth(access_token)
+ .request((err, res, body) => {
+ if (err) {
+ return reject(err);
+ }
+ resolve(body);
+ });
+ });
+ };
+
+ const getEmailRequest = () => {
+ return new Promise((resolve, reject) => {
+ linkedIn
+ .query()
+ .get('emailAddress?q=members&projection=(elements*(handle~))')
+ .auth(access_token)
+ .request((err, res, body) => {
+ if (err) {
+ return reject(err);
+ }
+ resolve(body);
+ });
+ });
+ };
+
+ const { localizedFirstName } = await getDetailsRequest();
+ const { elements } = await getEmailRequest();
+ const email = elements[0]['handle~'];
+
+ callback(null, {
+ username: localizedFirstName,
+ email: email.emailAddress,
+ });
+ } catch (err) {
+ callback(err);
+ }
+ break;
+ }
default:
callback({
message: 'Unknown provider.',