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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rmdes/indiekit-endpoint-linkedin

v1.0.5

Published

LinkedIn OAuth 2.0 endpoint for Indiekit — handles token acquisition through the UI

Readme

@rmdes/indiekit-endpoint-linkedin

LinkedIn OAuth 2.0 endpoint for Indiekit. Provides a UI-based flow to connect your LinkedIn account and manage access tokens.

Companion plugin to @rmdes/indiekit-syndicator-linkedin. This endpoint handles OAuth authorization and token management, while the syndicator uses those tokens to post to LinkedIn.

Originally based on work by Giacomo Debidda (jackdbd), from an unmerged pull request to the Indiekit monorepo.

Features

  • UI-based OAuth 2.0 authorization flow
  • Automatic token persistence in MongoDB
  • Token restoration on app restart
  • CSRF protection for OAuth callbacks
  • Reverse proxy compatibility (nginx, Caddy, Cloudron)
  • Status dashboard showing connection state and token expiry
  • Immediate token availability to syndicator via process.env

Installation

npm install @rmdes/indiekit-endpoint-linkedin

Requirements

  • A LinkedIn account with a registered application
  • Required OAuth scopes: openid, profile, w_member_social
  • Client ID and Client Secret (stored as environment variables or in config)
  • MongoDB configured in Indiekit (recommended for token persistence across restarts)

Usage

Add to your Indiekit configuration alongside the syndicator:

export default {
  plugins: [
    "@rmdes/indiekit-syndicator-linkedin",
    "@rmdes/indiekit-endpoint-linkedin",
  ],
  "@rmdes/indiekit-syndicator-linkedin": {
    authorName: "Your Name",
    authorProfileUrl: "https://www.linkedin.com/in/yourname",
    checked: true,
  },
};

Set your environment variables:

LINKEDIN_CLIENT_ID=your_client_id
LINKEDIN_CLIENT_SECRET=your_client_secret

OAuth Flow

  1. Navigate to /linkedin in the Indiekit UI
  2. Click "Connect to LinkedIn"
  3. Authorize the app on LinkedIn's consent page
  4. You're redirected back — the token is saved automatically
  5. The syndicator immediately picks up the new token

Tokens are persisted in MongoDB and restored automatically on app restart.

Options

| Option | Type | Default | Description | | -------------- | -------- | -------------------- | ------------------------------ | | clientId | string | env var | LinkedIn OAuth app Client ID | | clientSecret | string | env var | LinkedIn OAuth app Secret | | mountPath | string | "/linkedin" | URL path for the endpoint | | scopes | string[] | ["openid", ...] | OAuth 2.0 scopes |

LinkedIn App Setup

Step 1: Create a LinkedIn App

  1. Go to LinkedIn Developers
  2. Click "Create app" and fill in the required details:
    • App name: Your application name
    • LinkedIn Page: Select your company page (or create one)
    • Privacy policy URL: Your site's privacy policy
    • App logo: Upload a logo (optional)

Step 2: Configure OAuth Settings

  1. In your app dashboard, go to the Auth tab
  2. Under OAuth 2.0 settings, add your redirect URL:
    https://your-indiekit-domain/linkedin/callback
    • Important: Must be HTTPS in production (LinkedIn rejects HTTP callbacks)
    • Replace your-indiekit-domain with your actual domain
    • The path /linkedin/callback must match exactly (or use custom mountPath)

Step 3: Request Product Access

  1. Go to the Products tab
  2. Request access to these products:
    • Share on LinkedIn — Required for posting content
    • Sign In with LinkedIn using OpenID Connect — Required for authentication
  3. Wait for approval (usually instant for these products)

Step 4: Copy Credentials

  1. Go back to the Auth tab
  2. Copy your Client ID and Client Secret
  3. Add them to your environment variables:
    LINKEDIN_CLIENT_ID=your_client_id_here
    LINKEDIN_CLIENT_SECRET=your_client_secret_here

Troubleshooting App Setup

  • Redirect URI mismatch: Ensure the callback URL in your LinkedIn app settings matches exactly (protocol, domain, path)
  • Invalid scope: Make sure you've requested and been approved for "Share on LinkedIn" and "Sign In with LinkedIn"
  • App not verified: Some features may require app verification — check the Settings tab for verification status

How It Works

Token Flow

  1. User authorizes: Navigate to /linkedin and click "Connect to LinkedIn"
  2. OAuth redirect: Plugin redirects to LinkedIn's authorization page with CSRF protection
  3. User consents: User approves the requested permissions on LinkedIn
  4. Token exchange: LinkedIn redirects back with authorization code
  5. Token storage: Plugin exchanges code for access token and stores in:
    • MongoDB (persistent storage)
    • process.env.LINKEDIN_ACCESS_TOKEN (runtime access)
  6. Syndicator uses token: The syndicator plugin reads the token from process.env and uses it to post to LinkedIn

Relationship with Syndicator Plugin

This endpoint and the syndicator work together:

  • Endpoint (@rmdes/indiekit-endpoint-linkedin): Manages OAuth and stores tokens
  • Syndicator (@rmdes/indiekit-syndicator-linkedin): Uses tokens to post content to LinkedIn

The syndicator reads process.env.LINKEDIN_ACCESS_TOKEN, which is set by this endpoint. You can use the syndicator without this endpoint by manually setting the environment variable, but this endpoint provides a much better user experience.

Token Management

Token Expiry

LinkedIn access tokens expire after 60 days. The plugin displays the expiry date on the /linkedin status page. When your token expires:

  1. Navigate to /linkedin
  2. Click "Reconnect to LinkedIn"
  3. Authorize again to get a fresh token

Note: The plugin does not currently support automatic token refresh. You must manually reconnect when tokens expire.

Token Storage

Tokens are stored in two places:

  1. MongoDB collection (linkedin_tokens): Persistent storage that survives app restarts
  2. Process environment (process.env.LINKEDIN_ACCESS_TOKEN): Runtime access for the syndicator

On app startup, the plugin automatically restores the token from MongoDB to process.env.

Troubleshooting

"Not connected" status

Check:

  • Have you completed the OAuth flow via /linkedin?
  • Are your LINKEDIN_CLIENT_ID and LINKEDIN_CLIENT_SECRET set correctly?
  • Is MongoDB running and accessible?

Solution: Navigate to /linkedin and click "Connect to LinkedIn"

"State mismatch" error

Cause: Session not persisted between /auth and /callback requests

Check:

  • Is Indiekit session middleware configured?
  • Is session storage (Redis/MongoDB) running?

Solution: Ensure Indiekit has session storage configured in indiekit.config.js

"Redirect URI mismatch" error

Cause: The callback URL doesn't match what's registered in LinkedIn app

Check:

  • LinkedIn app callback URL: https://your-domain/linkedin/callback
  • If using custom mountPath, adjust callback URL accordingly

Solution: Update callback URL in LinkedIn Developer Portal to match exactly

Token exists but syndicator can't use it

Cause: Token stored in MongoDB but not loaded into process.env

Solutions:

  • Restart Indiekit (tokens are restored on startup)
  • Re-authorize via /linkedin (immediately sets process.env)

"Invalid scope" error

Cause: Requested OAuth scopes not approved for your LinkedIn app

Solution: Go to LinkedIn Developer Portal → Products tab → Request access to required products

Related Plugins

Documentation

  • CLAUDE.md — Comprehensive technical reference for developers working on this plugin
  • README.md (this file) — User-facing documentation for installing and using the plugin

Credits

This package is based on the LinkedIn endpoint originally written by Giacomo Debidda as an unmerged PR to the Indiekit monorepo. Extended with:

  • MongoDB token persistence
  • CSRF state validation
  • Reverse proxy header handling
  • Token expiry tracking
  • Improved error messages
  • Status dashboard UI

License

MIT