or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-passport-linkedin

LinkedIn authentication strategy for Passport using OAuth 1.0a

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/passport-linkedin@1.0.x

To install, run

npx @tessl/cli install tessl/npm-passport-linkedin@1.0.0

index.mddocs/

passport-linkedin

passport-linkedin is a Passport authentication strategy for integrating LinkedIn OAuth 1.0a authentication into Node.js applications. It allows applications to authenticate users through their LinkedIn accounts with configurable permission scopes and profile field selection.

Package Information

  • Package Name: passport-linkedin
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install passport-linkedin

Core Imports

// Default import (recommended)
const LinkedInStrategy = require('passport-linkedin');

Alternative imports:

// Named import
const { Strategy } = require('passport-linkedin');

// Explicit Strategy property access
const LinkedInStrategy = require('passport-linkedin').Strategy;

Basic Usage

const passport = require('passport');
const LinkedInStrategy = require('passport-linkedin');

passport.use(new LinkedInStrategy({
    consumerKey: 'YOUR_LINKEDIN_API_KEY',
    consumerSecret: 'YOUR_LINKEDIN_SECRET_KEY',
    callbackURL: 'http://localhost:3000/auth/linkedin/callback'
  },
  function(token, tokenSecret, profile, done) {
    // User authentication logic
    User.findOrCreate({ linkedinId: profile.id }, function (err, user) {
      return done(err, user);
    });
  }
));

// Routes
app.get('/auth/linkedin', passport.authenticate('linkedin'));

app.get('/auth/linkedin/callback',
  passport.authenticate('linkedin', { failureRedirect: '/login' }),
  function(req, res) {
    // Successful authentication
    res.redirect('/');
  });

Architecture

passport-linkedin extends Passport's OAuth 1.0a strategy with LinkedIn-specific customizations:

  • OAuth1 Foundation: Built on passport-oauth1 for standard OAuth 1.0a protocol handling
  • LinkedIn API Integration: Configured with LinkedIn-specific endpoints and request modifications
  • Scope Handling: Custom implementation to handle LinkedIn's URL parameter-based scope requests
  • Profile Normalization: Converts LinkedIn API responses to standardized Passport profile format
  • Field Mapping: Flexible system for requesting specific LinkedIn profile fields
  • Error Handling: LinkedIn-specific error detection and OAuth error wrapping

Capabilities

LinkedIn Strategy

Creates a new LinkedIn authentication strategy for Passport.

/**
 * LinkedIn authentication strategy constructor
 * @param {Object} options - Configuration options
 * @param {Function} verify - Verification callback function
 */
function Strategy(options, verify);

Options:

interface StrategyOptions {
  /** LinkedIn API consumer key (required) */
  consumerKey: string;
  /** LinkedIn API consumer secret (required) */
  consumerSecret: string;
  /** OAuth callback URL (required) */
  callbackURL: string;
  /** Specific profile fields to request (optional) */
  profileFields?: string[];
  /** Request token URL (optional) */
  requestTokenURL?: string;
  /** Access token URL (optional) */
  accessTokenURL?: string;
  /** User authorization URL (optional) */
  userAuthorizationURL?: string;
  /** Session key for OAuth tokens (optional) */
  sessionKey?: string;
}

Verify Callback:

/**
 * Verification callback function
 * @param {string} token - OAuth access token
 * @param {string} tokenSecret - OAuth token secret
 * @param {Object} profile - User profile object
 * @param {Function} done - Completion callback
 */
function verify(token, tokenSecret, profile, done);

Extended Permissions

Request extended permissions using the scope parameter during authentication.

// Single scope
app.get('/auth/linkedin',
  passport.authenticate('linkedin', { scope: 'r_fullprofile' }));

// Multiple scopes
app.get('/auth/linkedin',
  passport.authenticate('linkedin', { 
    scope: ['r_basicprofile', 'r_emailaddress'] 
  }));

Profile Field Selection

Configure specific profile fields to request from LinkedIn API.

passport.use(new LinkedInStrategy({
    consumerKey: 'YOUR_API_KEY',
    consumerSecret: 'YOUR_SECRET',
    callbackURL: 'http://localhost:3000/auth/linkedin/callback',
    profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline']
  },
  function(token, tokenSecret, profile, done) {
    // Handle authentication
    return done(null, profile);
  }
));

Strategy Methods

authenticate

Handles the OAuth authentication flow and processes LinkedIn responses. Extends the base OAuth1 strategy authentication with LinkedIn-specific error handling.

/**
 * Authenticate request using LinkedIn OAuth
 * @param {Object} req - HTTP request object  
 * @param {Object} options - Authentication options (scope, etc.)
 * @returns {void} - Calls success(), fail(), or error() on completion
 */
Strategy.prototype.authenticate(req, options);

Special behavior:

  • Detects oauth_problem=user_refused query parameter and calls fail() for user denial
  • Delegates to parent OAuth1Strategy for standard OAuth flow
  • Handles LinkedIn-specific OAuth token request modifications for scope parameter

userProfile

Retrieves user profile information from LinkedIn API.

/**
 * Retrieve user profile from LinkedIn
 * @param {string} token - OAuth access token
 * @param {string} tokenSecret - OAuth token secret
 * @param {Object} params - Additional parameters
 * @param {Function} done - Completion callback with (err, profile)
 */
Strategy.prototype.userProfile(token, tokenSecret, params, done);

requestTokenParams

Returns LinkedIn-specific parameters for request token requests, with special handling for scope parameters.

/**
 * Return extra LinkedIn-specific parameters for request token request
 * @param {Object} options - Options containing scope information
 * @param {string|string[]} options.scope - LinkedIn permission scope(s)
 * @returns {Object} Parameters object with scope handling
 */
Strategy.prototype.requestTokenParams(options);

Scope handling:

  • String scopes are passed directly: 'r_basicprofile'
  • Array scopes are joined with '+': ['r_basicprofile', 'r_emailaddress']'r_basicprofile+r_emailaddress'
  • LinkedIn expects scope as URL query parameter, not in POST body (handled automatically)

Types

Profile Object

The profile object returned by LinkedIn contains normalized user information:

interface LinkedInProfile {
  /** Always 'linkedin' */
  provider: string;
  /** LinkedIn user ID */
  id: string;
  /** Full display name (firstName + lastName) */
  displayName: string;
  /** Name breakdown */
  name: {
    /** Last name */
    familyName: string;
    /** First name */
    givenName: string;
  };
  /** Email addresses (if requested via profileFields) */
  emails?: Array<{
    /** Email address value */
    value: string;
  }>;
  /** Raw API response body */
  _raw: string;
  /** Parsed JSON response */
  _json: {
    /** LinkedIn user ID */
    id: string;
    /** First name from LinkedIn */
    firstName: string;
    /** Last name from LinkedIn */
    lastName: string;
    /** Email address (if requested) */
    emailAddress?: string;
    /** Additional fields based on profileFields configuration */
    [key: string]: any;
  };
}

Strategy Instance Properties

interface StrategyInstance {
  /** Strategy name, always 'linkedin' */
  name: string;
}

Profile Field Mapping

Standard profile field names are mapped to LinkedIn API fields:

  • 'id''id'
  • 'name'['first-name', 'last-name']
  • 'emails''email-address'

Unmapped field names are passed directly to the LinkedIn API, allowing access to additional LinkedIn profile data.

Profile Field Conversion

The strategy internally converts profile field names using a mapping system:

/**
 * Internal method to convert profile field names to LinkedIn API format
 * @param {string[]} profileFields - Array of profile field names
 * @returns {string} Comma-separated LinkedIn API field names
 * @private
 */
Strategy.prototype._convertProfileFields(profileFields);

Example conversions:

  • ['id', 'name', 'emails']'id,first-name,last-name,email-address'
  • ['id', 'headline', 'industry']'id,headline,industry' (unmapped fields passed through)

This enables flexible profile data collection while maintaining compatibility with standard field names.

Error Handling

The strategy handles common error scenarios:

  • User Denial: When users deny authorization, the strategy detects oauth_problem=user_refused parameter and calls fail()
  • Profile Fetch Errors: API errors during profile retrieval are wrapped in InternalOAuthError from passport-oauth1
  • Invalid Responses: JSON parsing errors during profile processing are passed to the done callback

InternalOAuthError

/**
 * OAuth-specific error wrapper from passport-oauth1
 * @param {string} message - Error description
 * @param {Error} err - Original error object
 */
class InternalOAuthError extends Error {
  constructor(message, err);
  /** OAuth error details */
  oauthError: Error;
}

Scope Values

Common LinkedIn permission scopes:

  • r_basicprofile - Basic profile information
  • r_emailaddress - Email address
  • r_fullprofile - Full profile access
  • w_messages - Send messages
  • rw_company_admin - Company administration

Multiple scopes are joined with '+' when sent to LinkedIn API.