React: LinkedIn Access Token in 10 Steps

I recently integrated with the LinkedIn API, and it turned out to be pretty straightforward. The task was to retrieve the user’s email address from LinkedIn. To achieve this, I primarily used two endpoints:

  • https://api.linkedin.com/oauth/v2/authorization

  • https://www.linkedin.com/oauth/v2/accessToken

Prerequisite

To get this working, you’ll need a LinkedIn App, which is easy to set up via the LinkedIn Developer Portal. Once created, your app will provide:

  • Client ID: A unique identifier for your app.
  • Client Secret: Used for secure communication between your app and LinkedIn.

Additionally, you’ll need to set up a Redirect URL. This is where LinkedIn sends the authorization code after the user approves your app

LinkedIn Developer Application Setup

How to Get a LinkedIn Access Token in 10 Steps

Two endpoints, right? But to make it all work, there are at least 10 steps involved. Take a look at the sequence diagram:

LinkedIn Access Token Sequence Diagram

Step 1: User clicks the Authorize button.

Step 1: Click Authorize

Step 2: The web application redirects the user to LinkedIn.

You need to redirect the user to:

https://api.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=profile%20email%20openid

Replace CLIENT_ID and REDIRECT_URI with your values defined in the developer portal.

Step 3: LinkedIn asks the user to log in

Step two: linkedIn log in

Step 4: LinkedIn asks the user to authorize the web application

Step 5: LinkedIn sends the user to the redirect URL.

In my case, the final redirect URL looks like this:

https://demo.garciadiazjaime.com/linkedin-api-openid-user-info?code=AQSWHfrKRe6Zvr-fSccBQl2FfpxdkPxx6penQgLAFuNWVXviCb2qmtuCdy9czV-vZIqIczV-4UQNcKuRQk1qMgA3c13CdPpGHxdItcpqMuMmJsksxXYLOohcBF7jaAAqA6nKMq6pXsLH5-itSnyGdnWVIDc1v1ynAzckv-DCOn1gP6lkQf8aWu3CM5E79Zoh8PmHS3_eWT0LymNSM7U

Notice how the code query parameter is passed. This is important because it will be used in the next step when requesting the access token.

Step 6: The web application passes the code to a Lambda function

The reason for using a Lambda function here is that the next step involves requesting an access token, which requires passing the Client ID and Client Secret. Since these credentials should remain secure, this step needs to be handled in a backend-like environment.

Step 7: Lambda Function Requests an Access Token from LinkedIn

Take a look at the code:

const { code } = JSON.parse(event.body);

const config = {
  grant_type: "authorization_code",
  code,
  client_id: LINKEDIN_CLIENT_ID,
  client_secret: LINKEDIN_CLIENT_SECRET,
  redirect_uri: LINKEDIN_REDIRECT,
};

const response = await fetch(`https://www.linkedin.com/oauth/v2/accessToken`, {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams(config),
});

Step 8. LinkedIn returns the token to the Lambda function

Step 9. Lambda function returns the token to the web application

Step 10. Web application receives the token

The LinkedIn response for the oauth/v2/accessToken endpoint typically looks like this:

{
  access_token:"...access_token...",
  expires_in: 5183999,
  scope: "email,openid,profile",
  token_type: "Bearer",
  id_token:
    "eyJ6aXAiOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImQ5Mjk2NjhhLWJhYjEtNGM2OS05NTk4LTQzNzMxNDk3MjNmZiIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJodHRwczovL3d3dy5saW5rZWRpbi5jb20vb2F1dGgiLCJhdWQiOiI4NmNtemNrN2k2dG5tOCIsImlhdCI6MTczMTg4MDM1MCwiZXhwIjoxNzMxODgzOTUwLCJzdWIiOiJlbTVqVXhDcEh4IiwibmFtZSI6IkphaW1lIEdhcmNpYSBEaWF6IiwiZ2l2ZW5fbmFtZSI6IkphaW1lIiwiZmFtaWx5X25hbWUiOiJHYXJjaWEgRGlheiIsInBpY3R1cmUiOiJodHRwczovL21lZGlhLmxpY2RuLmNvbS9kbXMvaW1hZ2UvdjIvQzU2MDNBUUhnYWc5TVNUUDNGQS9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfMTAwXzEwMC9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfMTAwXzEwMC8wLzE2NjA5MzcwNTQ2MTg_ZT0yMTQ3NDgzNjQ3JnY9YmV0YSZ0PXpuRWFMUS1vSVRYVl9LT3B5aFZGcDRfUHVLd0JabGx5VGRjNTc3ZDBoWXciLCJlbWFpbCI6ImdhcmNpYWRpYXpqYWltZUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJsb2NhbGUiOiJlbl9VUyJ9...",
};

Notice how id_token is included in the response, and this is a JWT (JSON Web Token). If you decode it, you’ll get something like this:

import { jwtDecode } from "jwt-decode";

jwtDecode(jwt);

which among other things it outputs:

{
  "email": "[email protected]",
  "given_name": "name",
  ...
}

For my use case, the email field is exactly what I needed. Now that you have the access token, you can also use it to make requests to the LinkedIn REST API, like this:

const response = await fetch(`https://api.linkedin.com/v2/userinfo`, {
  method: "GET",
  headers: {
    Authorization: access_token,
  },
});

const user = await response.json();

It’ll give you basically the same info as in the JWT token, but now that you have the access token, you can use it to access any of LinkedIn’s other endpoints.

Conclusion

Overall, integrating with LinkedIn’s RESTful API was pretty straightforward. One thing to keep in mind is that the process is split between the client and server: the client handles redirecting the user to LinkedIn for authentication and authorization, while the server is responsible for interacting with LinkedIn’s API and passing the ClientId and ClientSecret which should not be exposed in your client application.