For a personal project, I need API access to my Feedly account.

Previously, with a paid Feedly account you could generate an API token for programmatic API access.

Now, Feedly locks this feature behind an Enterprise account ($2,400/month, billed annually).

So I needed to find another way to get API access.

Browser Dev Tools

My first idea was to copy the Feedly Authorization header from my browser’s network tools. But this token expires after a few days.

OAuth Applications

My second idea was to create a personal Feedly OAuth application, but this is locked behind approval from Feedly.

My workaround was to leverage an existing OAuth application and copy the OAuth refresh token used by the application.

NetNewsWire is an open source RSS Reader for macOS with Feedly support.

Since NetNewsWire uses OAuth to connect to the Feedly API, I can extract the OAuth credentials for my own use.

Apple Keychain

After logging into my Feedly account with NetNewsWire, I found two cloud.feedly.com “Internet Password” entries in “Keychain Access.app”.

One of these is the OAuth Access Token, and the second is the OAuth Refresh Token.

Sadly, these two credentials aren’t enough to generate a new access token.

We need the OAuth Client ID for the NetNewsWire Feedly OAuth application, and the OAuth Client Secret.

Charles Proxy

Using a man-in-the-middle proxy, Charles Proxy, I was able to intercept the web traffic between NetNewsWire and the Feedly OAuth API.

From this, I was able to extract all of the OAuth credentials necessary to generate a new OAuth Access Token.

I observed a request to the /v3/auth/token endpoint which contained the OAuth client_id and client_secret.

POST https://cloud.feedly.com/v3/auth/token
{
	"redirect_uri": "netnewswire:\/\/auth\/feedly",
	"client_id": "<NetNewsWire-client-id>",
	"code": "<fac_code>",
	"client_secret": "<NetNewsWire-client-secret>",
	"scope": "https:\/\/cloud.feedly.com\/subscriptions",
	"grant_type": "authorization_code"
}

The response contained an OAuth refresh_token and access_token.

{
  "id": "<my-feedly-user-id>",
  "provider": "Google",
  "is_new_account": false,
  "plan": "proPlus",
  "scope": "https://cloud.feedly.com/subscriptions",
  "refresh_token": "<refresh:token>",
  "access_token": "<JWE.token.here>",
  "token_type": "bearer",
  "expires_in": 604800
}

Now with all of the required information, I could call the Feedly API myself and generate a new OAuth access token.

curl -X POST https://cloud.feedly.com/v3/auth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<feedly-refresh-token>" \
  -d "client_id=<feedly-client-id>" \
  -d "client_secret=<feedly-client-secret>"