This guide explains our LinkedIn integration: scopes, OAuth 2.0 Authorization Code flow, data persisted, how we determine the author URN, and how publishing works.
Quick links: Frontend β’ Backend
Permissions and scopesβ
Default scopes requested:
w_member_social(posting via UGC)openid profile(basic member profile via OIDC userinfo)
Backendβ
Token and profile flowβ
- Start:
liAuthStart
- Requires Firebase ID token; verifies to get
uid. - Stores
oauthStates/{state}with{ uid, provider: 'linkedin', returnTo }. - Redirects to
https://www.linkedin.com/oauth/v2/authorizationwithresponse_type=code,client_id,redirect_uri,scope,state.
- Callback:
liAuthCallback
- Exchanges
codefor tokens atPOST https://www.linkedin.com/oauth/v2/accessTokenwith form fieldsgrant_type=authorization_code,code,redirect_uri,client_id,client_secret. - Retrieves a compact profile using
GET https://api.linkedin.com/v2/userinfo(preferred) or falls back toGET https://api.linkedin.com/v2/me. - Computes
authorUrnasurn:li:person:{id}. - Persists to
users/{uid}/integrations/linkedin/{personId}(wherepersonIdfrom profile):accountId: Unique identifier (same as person ID)accessToken,tokenType='bearer',scope,expiresIn,expiresAt,updatedAtprofile(platformId/displayName/username/avatarUrl)authorUrnenabled_for_repost: (optional) boolean flag for automatic reposting
- Redirects to
returnTo?linkedin=connectedif provided.
Multi-Account Supportβ
Users can connect multiple LinkedIn accounts. Each account is stored separately with a unique accountId.
Storage path: users/{uid}/integrations/linkedin/{accountId}
Where accountId is the LinkedIn person ID.
Account selection:
- If user has one account: Automatically selected, no
accountIdrequired in API requests - If user has multiple accounts:
accountIdis required in API requests (e.g.,/v1/posts) - Missing required
accountIdreturns400error with codemissing_account
Publishingβ
Endpoint: Cloud Function publishLinkedin (via orchestrator)
Flow:
- Resolve account: Determine
accountIdfrom request or auto-select if only one account exists - Load
users/{uid}/integrations/linkedin/{accountId}; ensureaccessToken. - Resolve/repair
authorUrnvia OIDC userinfo or/v2/meif missing; persist when repaired. - Compose UGC Post for text:
author: urn:li:person:{id}
lifecycleState: PUBLISHED
specificContent:
com.linkedin.ugc.ShareContent:
shareCommentary: { text }
shareMediaCategory: NONE
visibility:
com.linkedin.ugc.MemberNetworkVisibility: PUBLIC
- POST
https://api.linkedin.com/v2/ugcPostswith Bearer token andX-Restli-Protocol-Version: 2.0.0. - On success, store result id (
x-restli-idheader or response body) and record the user post.
Errors are logged with structured fields; function returns 400 with upstream body on LinkedIn API errors.
Frontendβ
Hooks/services under apps/web/src/features/integrations initiate connect and fanβout publishing through the orchestrator.