npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@authial/linkedin

v1.1.0

Published

LinkedIn OAuth 2.0 authentication strategy for Passport with TypeScript support.

Readme

LinkedIn OAuth 2.0 authentication strategy for Passport with TypeScript support

Authenticates users via LinkedIn’s 3-legged OAuth 2.0 flow, handling the authorization process and retrieval of user profile information.

Important notes

  • LinkedIn access tokens are typically valid for 60 days for non-MDP (Marketing Developer Platform) partners.
  • Refresh tokens are not provided unless your app is approved as an MDP partner.
  • You should calculate token expiration as current_date + 60 days and store it in your database.
  • When tokens expire, users must re-authenticate through the same OAuth flow.

Required options

  • clientID – Your LinkedIn application’s Client ID (from the LinkedIn Developer Portal).
  • clientSecret – Your LinkedIn application’s Client Secret (keep this secure).
  • callbackURL – The URL LinkedIn redirects to after user authorization.

Optional configuration

  • scope – Array of permissions (default: ['openid', 'profile', 'email']).
  • state – Enable CSRF protection (recommended: true).
  • userProfileURL – Custom profile endpoint (default: LinkedIn’s v2 userinfo).

Usage

Before using this application, you must first set up an app on LinkedIn Developer Portal. Here’s a step-by-step guide:

  1. Create a LinkedIn App:

    • Visit the LinkedIn Developer Portal.
    • Sign in with your LinkedIn account.
    • Click on "Create app" and fill in the required details such as your app's name, description, and logo.
  2. Get Your Client ID and Client Secret:

    • Once your app is created, you’ll find your Client ID and Client Secret in the app settings. Keep these credentials secure.
  3. Set Up Required Scopes:

    • In your app settings, navigate to the "Auth" tab.
    • Under the "OAuth 2.0 settings," you will find a list of available scopes. Choose the scopes as per your application's requirements and add the Redirect URI that will handle JSON responses from LinkedIn.
    • Default scopes such as openid, profile, and email are already included when you set up your app.
  4. Authentication:

    • Use the obtained Client ID and Client Secret in your application to authenticate users and access LinkedIn data as per the configured scopes.

Make sure you handle the authentication flow correctly in your application to ensure users can sign in and authorize access appropriately.

Example: basic usage with token expiration

import passport from 'passport';
import { Strategy as LinkedInStrategy } from '@authial/passport-linkedin';

passport.use(
  new LinkedInStrategy(
    {
      clientID: process.env.LINKEDIN_CLIENT_ID!,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET!,
      callbackURL: 'https://yourapp.com/auth/linkedin/callback',
      scope: ['openid', 'profile', 'email', 'w_member_social'],
      state: true, // Enable CSRF protection
    },
    async (accessToken, refreshToken, profile, done) => {
      try {
        // Calculate token expiration (60 days from now for non-MDP partners)
        const tokenExpiresAt = new Date();
        tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 60);

        // Save user and token info to your database
        const user = await db.user.upsert({
          where: { linkedinId: profile.id },
          update: {
            accessToken,
            tokenExpiresAt, // Store when token expires
            email: profile.emails?.value,
            displayName: profile.displayName,
          },
          create: {
            linkedinId: profile.id,
            accessToken,
            tokenExpiresAt,
            email: profile.emails?.value,
            displayName: profile.displayName,
          },
        });

        // Note: refreshToken will be undefined for non-MDP partners
        return done(null, user);
      } catch (error) {
        return done(error);
      }
    },
  ),
);

Example: middleware to handle token expiration

// Middleware to check if LinkedIn token is still valid
async function validateLinkedInToken(req, res, next) {
  const user = await db.user.findUnique({ where: { id: req.user.id } });

  if (!user?.accessToken || Date.now() >= user.tokenExpiresAt.getTime()) {
    // Token expired - redirect or instruct client to re-auth
    return res.status(401).json({
      error: 'LinkedIn token expired',
      message: 'Please re-authorize with LinkedIn',
      redirectUrl: '/auth/linkedin', // Same OAuth flow
    });
  }

  req.user.accessToken = user.accessToken;
  next();
}

// Use in protected routes
app.get('/api/linkedin/profile', validateLinkedInToken, async (req, res) => {
  // Make LinkedIn API calls with a valid token
});

Authors

References

  • LinkedIn OAuth 2.0 Authorization Code Flow: https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow
  • LinkedIn Developer Portal: https://developer.linkedin.com