Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] LinkedIn endpoint and syndicator #752

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

jackdbd
Copy link
Contributor

@jackdbd jackdbd commented Jun 6, 2024

This PR addresses issue #531

Warning

This PR is still a work in progress.

LinkedIn APIs, LinkedIn OAuth app, LinkedIn page

LinkedIn has several APIs (they call them API products).

In order to use any LinkedIn API we must create a LinkedIn OAuth app.

We also must associate a LinkedIn OAuth app with a LinkedIn page. However, we don't have to create a LinkedIn page ourselves, and we can use the Default Company Page (for API testing) instead.

linkedin-app

Creating posts on LinkedIn

In order to create posts on LinkedIn we need to call the CREATE method of the LinkedIn Posts API. The CREATE method, like most other methods of this LinkedIn API, requires the OAuth 2.0 Authorization Code Flow (also called 3-legged OAuth). In order to create a LinkedIn post, the access token sent with the request needs to have the w_member_social scope.

linkedin-posts

The Posts API allows each LinkedIn OAuth app to create, each day, up to 500 posts per user, and up to 150,000 posts in total.

linkedin-quotas

How to obtain an access token?

In production the user needs to go through the OAuth 2.0 flow. See example with simple-oauth2.

In development we can generate a LinkedIn access token using the OAuth Token Generator tool.

If you get this error in Chrome...

Oops. We can’t verify the authenticity of your request because the state parameter was modified

...try generating the token in Incognito mode as suggested here.

All access tokens issued by LinkedIn have an expiration of 60 days.

Useful links

@jackdbd jackdbd marked this pull request as draft June 6, 2024 15:45
@jackdbd jackdbd force-pushed the feat/531-linkedin-syndicator branch from 4a80a05 to bb2c548 Compare June 6, 2024 21:24
@jackdbd
Copy link
Contributor Author

jackdbd commented Jun 6, 2024

At the moment this syndicator works, but relies on an access token created using the LinkedIn OAuth Token Generator Tool (the token has an expiration of 60 days).

Indiekit

  1. The user writes a new note.

syndication-note-create

  1. The user optionally assigns a slug.

syndication-note-slug

  1. The user decides that this note will be syndicated to LinkedIn (and Mastodon).

syndication-note-syndicate-to

  1. The user clicks the Syndicate post button in the detail page of the note.

  2. The post appears on LinkedIn. TODO: how to format the text for LinkedIn (i.e. bold, links)?

syndication-note-on-linkedin

  1. The URL of the content syndicated to LinkedIn appears in the detail page of the note.

syndication-url-in-indiekit

@jackdbd jackdbd force-pushed the feat/531-linkedin-syndicator branch from bb2c548 to cc273c3 Compare June 7, 2024 13:45
@jackdbd
Copy link
Contributor Author

jackdbd commented Jun 7, 2024

I created a new package endpoint-linkedin. This package includes the following routes:

  1. oauth/linkedin: launches the Authorization Code Flow (3-legged OAuth).
  2. oauth/linkedin/start: redirects to the consent screen of the LinkedIn OAuth app.
  3. oauth/linkedin/callback: receives the LinkedIn request, extracts the authorization code and exchanges it for a LinkedIn access token. The LinkedIn access token is then persisted in the environment variable LINKEDIN_ACCESS_TOKEN.

The authorization flow starts when the user visits this page (I'm not very familiar with the codebase, so I just created a super simple view with nunjucks).

indiekit-authorize-linkedin-page

To quickly reach that page, I added a link in the welcome page.

indiekit-link-to-linkedin-oauth

When the user wants to allow Indiekit—or more precisely, the LinkedIn OAuth app they created for their Indiekit installation—they visit the authorization page on Indiekit, that redirects them to the LinkedIn consent screen.

linkedin-oauth-consent-screen-openid-profile-w_member_social

Note: the user first needs to create a LinkedIn OAuth app with the required OAuth scopes and the required callback URL.

linkedin-token-generator

linkedin-app-callback-url

Tip

If the LinkedIn OAuth app is created with the scope openid, it also requires at least one another scope among profile and email. An app that has a openid scope issues both an access_token and an id_token.

@jackdbd jackdbd force-pushed the feat/531-linkedin-syndicator branch from cc273c3 to f51cfd7 Compare June 7, 2024 14:45
@jackdbd jackdbd changed the title [WIP] LinkedIn syndicator [WIP] LinkedIn endpoint and syndicator Jun 7, 2024
@paulrobertlloyd
Copy link
Collaborator

Ooooh, I’ve longed thought about having UI-based OAuth for adding syndicators – this is so cool!

I think I’d be tempted to have this encapsulated in one plugin (plugins can provide endpoints as well a syndication methods, if needed).

I’d also be curious to know what, if anything, could be provided by Indiekit’s core (or a first-party plugin) to support building OAuth flows in the UI/application, so that this functionality could be added to other syndicators/content stores etc.

@jackdbd
Copy link
Contributor Author

jackdbd commented Jun 10, 2024

plugins can provide endpoints as well a syndication methods, if needed.

Yes, I think it makes sense to keep the endpoints for the OAuth flow and the syndication logic in the same plugin. I just didn't know how to organize the code in Indiekit.

so that this functionality could be added to other syndicators/content stores etc.

Absolutely. Most OAuth logic should be reusable across syndicators. I think most social networks (LinkedIn, Twitter, Reddit, etc) allow posting on the user's behalf using a OAuth 2.0 Authorization Code Flow (3-legged OAuth). I used the simple-oauth2 library to avoid implementing the entire OAuth 2.0 flow from scratch. I thought about putting the link to start the OAuth flow in the syndicator detail page: the user visits that page, gets redirected to the OAuth consent screen, clicks allow, returns the syndicator detail page. The user flow would be the same for other syndicators that require an OAuth flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request plugin-syndicator Syndicator plug-in
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants