Remix Auth Linkedin Strategy
This library provides a LinkedIn authentication strategy for `remix-auth`, enabling users to log into Remix applications via their LinkedIn accounts. It extends `remix-auth-oauth2` and is currently at version 2.0.1, shipping with full TypeScript definitions for robust development. The package maintains a steady release cadence, with recent updates focused on dependency upgrades and critical API changes. A significant update in version 2.0.0 involved transitioning from LinkedIn's legacy OAuth 2.0 flow to the newer OpenID Connect standard, reflecting LinkedIn's evolving authentication protocols. This change required corresponding adjustments in application setup and profile handling. `remix-auth-linkedin` supports both Node.js and Cloudflare runtimes, making it versatile for various Remix deployment environments. Developers must register an OAuth application on the LinkedIn Developers page to obtain the necessary `clientID` and `clientSecret` for integration. It seamlessly integrates with `remix-auth`'s session management, leveraging `createCookieSessionStorage` or similar for authentication persistence.
Common errors
-
Error: Missing or invalid client ID/secret
cause The `clientID` or `clientSecret` provided to `LinkedinStrategy` is incorrect or missing, preventing successful authentication with the LinkedIn API.fixVerify your `clientID` and `clientSecret` values against your LinkedIn developer application settings. Ensure they are correctly passed to the `LinkedinStrategy` constructor and are loaded from secure environment variables. -
Error: Invalid redirect_uri
cause The `callbackURL` configured in `LinkedinStrategy` does not precisely match one of the authorized redirect URIs configured in your LinkedIn developer application.fixEnsure the `callbackURL` passed to `LinkedinStrategy` (e.g., `https://example.com/auth/linkedin/callback`) exactly matches an authorized redirect URI in your LinkedIn developer application settings, including protocol, domain, and path. -
TypeError: authenticator.authenticate is not a function
cause The `Authenticator` instance was not properly initialized, the `linkedinStrategy` was not correctly `use`d with the authenticator, or the strategy name ('linkedin') is misspelled in the `authenticate` call.fixConfirm that `export const authenticator = new Authenticator(...)` is executed, that `authenticator.use(linkedinStrategy, 'linkedin')` is called, and that the strategy name 'linkedin' is consistently used in all `authenticator.authenticate` calls.
Warnings
- breaking Version 2.0.0 of `remix-auth-linkedin` migrated from LinkedIn's traditional OAuth 2.0 implementation to OpenID Connect. This is a breaking change that requires re-evaluation of how user profile data is structured and potentially changes to your LinkedIn application settings.
- gotcha The `callbackURL` provided to the `LinkedinStrategy` must be a complete, absolute URL (e.g., `https://example.com/auth/linkedin/callback`), not a relative path. LinkedIn's API expects a fully qualified URL for redirects.
- gotcha Client ID and Client Secret should never be hardcoded or exposed directly in client-side code. Always retrieve them from secure environment variables or a secrets management service to prevent security vulnerabilities.
- gotcha The `secrets` array for `createCookieSessionStorage` must contain robust, unique, and long-lived secret strings. Using placeholder values like `THISSHOULDBESECRET_AND_NOT_SHARED` in production is a significant security vulnerability.
Install
-
npm install remix-auth-linkedin -
yarn add remix-auth-linkedin -
pnpm add remix-auth-linkedin
Imports
- LinkedinStrategy
const { LinkedinStrategy } = require("remix-auth-linkedin");import { LinkedinStrategy } from "remix-auth-linkedin"; - Authenticator
import Authenticator from "remix-auth";
import { Authenticator } from "remix-auth"; - createCookieSessionStorage
import { createCookieSessionStorage } from 'remix';import { createCookieSessionStorage } from '@remix-run/node';
Quickstart
import { createCookieSessionStorage } from '@remix-run/node';
import { Authenticator } from 'remix-auth';
import { LinkedinStrategy } from "remix-auth-linkedin";
// Personalize this options for your usage.
const cookieOptions = {
path: '/',
httpOnly: true,
sameSite: 'lax' as const,
maxAge: 24 * 60 * 60 * 1000 * 30,
secrets: [process.env.SESSION_SECRET ?? 'fallback_secret_for_dev_only'], // Use env variable for production
secure: process.env.NODE_ENV !== 'development',
};
const sessionStorage = createCookieSessionStorage({
cookie: cookieOptions,
});
export const authenticator = new Authenticator<string>(sessionStorage, {
throwOnError: true,
});
const linkedinStrategy = new LinkedinStrategy(
{
clientID: process.env.LINKEDIN_CLIENT_ID ?? 'YOUR_CLIENT_ID_FROM_ENV',
clientSecret: process.env.LINKEDIN_CLIENT_SECRET ?? 'YOUR_CLIENT_SECRET_FROM_ENV',
callbackURL: process.env.LINKEDIN_CALLBACK_URL ?? 'https://example.com/auth/linkedin/callback',
},
async ({accessToken, refreshToken, extraParams, profile, context}) => {
// In a real application, you would interact with your database or API here
// For example, finding or creating a user based on the LinkedIn profile
console.log('LinkedIn Profile:', profile.id, profile.displayName, profile.emails[0].value);
console.log('Access Token:', accessToken);
// Simulate user data storage
return { id: profile.id, email: profile.emails[0].value, name: profile.displayName };
}
);
authenticator.use(linkedinStrategy, 'linkedin');
// app/routes/login.tsx
// export default function Login() {
// return (
// <form action="/auth/linkedin" method="post">
// <button>Login with Linkedin</button>
// </form>
// )
// }
// app/routes/auth/linkedin.tsx
// import { ActionFunction } from '@remix-run/node';
// import { authenticator } from '~/linkedin.server'; // Adjust path
//
// export let loader: ActionFunction = () => { throw new Response(null, { status: 404 }); }; // Loader is not strictly needed here
// export let action: ActionFunction = ({ request }) => {
// return authenticator.authenticate('linkedin', request);
// };
// app/routes/auth/linkedin/callback.tsx
// import { LoaderFunction } from '@remix-run/node';
// import { authenticator } from '~/linkedin.server'; // Adjust path
//
// export let loader: LoaderFunction = ({ request }) => {
// return authenticator.authenticate('linkedin', request, {
// successRedirect: '/dashboard',
// failureRedirect: '/login',
// });
// };