LinkedIn integration fails with 403 error when fetching profile picture
📜 Description
LinkedIn integration (both personal profile and LinkedIn Page) fails during the OAuth callback process. After successful OAuth authentication, Postiz attempts to fetch the user's profile picture from LinkedIn's CDN, which returns a 403 Forbidden error. This causes the entire integration to fail and the LinkedIn account is not added to Postiz.
👟 Reproduction steps
Reproduction steps:
- Go to Postiz dashboard
- Click on "Add Channel"
- Select either "LinkedIn" or "LinkedIn Page"
- Complete OAuth authentication on LinkedIn (successfully)
- Get redirected back to Postiz
- See error message: "Could not add provider. You are being redirected back"
- Check logs to see: "AxiosError: Request failed with status code 403" at LocalStorage.uploadSimple
👍 Expected behavior
After OAuth authentication, the LinkedIn integration should be saved successfully, even if the profile picture cannot be fetched. The integration should handle profile picture fetch failures gracefully and continue with the integration setup.
👎 Actual Behavior with Screenshots
The integration fails completely when LinkedIn's CDN returns 403 for profile picture access. Error in logs:
[ERROR] [ExceptionsHandler] Request failed with status code 403 AxiosError: Request failed with status code 403 at async LocalStorage.uploadSimple (/app/apps/backend/dist/libraries/nestjs-libraries/src/upload/local.storage.js:14:27) at async IntegrationService.createOrUpdateIntegration (/app/apps/backend/dist/libraries/nestjs-libra ries/src/database/prisma/integrations/integration.service.js:54:19)
The integration is not saved and users cannot connect their LinkedIn accounts.
💻 Operating system
Linux
🤖 Node Version
Node 20.18.1 (as per container environment)
📃 Provide any additional context for the Bug.
- Postiz version: v2.5.4 (using ghcr.io/gitroomhq/postiz-app:latest)
- LinkedIn App configuration is correct with proper redirect URIs
- OAuth authentication completes successfully
- Issue occurs when trying to fetch/save profile picture from LinkedIn
- LinkedIn has restricted access to profile pictures via their CDN
- Affects both personal LinkedIn and LinkedIn Page integrations
- Environment variables properly configured:
- LINKEDIN_CLIENT_ID and LINKEDIN_CLIENT_SECRET are set
- All URLs (FRONTEND_URL, BACKEND_URL, etc.) are correctly configured
- This appears to be related to LinkedIn's API changes regarding profile picture access
👀 Have you spent some time to check if this bug has been raised before?
- [x] I checked and didn't find similar issue
Are you willing to submit PR?
None
I'm under the impression that I've got this bug too.
Every other integration works perfectly, I'm using threads, Instagram and X. A couple of days ago, when I tried to renew my Linkedin service I kept getting the "Could not add provider" message over and over again. I'm unable to reconnect it nor add the channel again.
I'm under the impression that I've got this bug too.
Every other integration works perfectly, I'm using threads, Instagram and X. A couple of days ago, when I tried to renew my LinkedIn service I kept getting the "Could not add provider" message over and over again. I'm unable to reconnect it nor add the channel again.
Nevermind it seems to be working again, I reinstalled my docker-compose image and it seemed to work. I connected the service successfully and I was able to post (at least no errors so far)
Solution: https://github.com/gitroomhq/postiz-app/issues/918#issuecomment-3254171711
I installed today, and the solution noted above is void as my backend is/was already set correctly (BACKEND_INTERNAL_URL: "http://localhost:3000") and it still does not work correctly.
This is still not working correctly. The provided patch allows the channel to be added, but the profile images are getting 403 error. Not sure if it isn't just Cloudflare cutting the user agent: `postiz | 2|backend | response: { postiz | 2|backend | status: 403, postiz | 2|backend | statusText: 'Forbidden', postiz | 2|backend | headers: Object [AxiosHeaders] { postiz | 2|backend | date: 'Thu, 06 Nov 2025 14:52:20 GMT', postiz | 2|backend | 'content-type': 'text/html; charset=UTF-8', postiz | 2|backend | 'transfer-encoding': 'chunked', postiz | 2|backend | connection: 'keep-alive', postiz | 2|backend | 'x-frame-options': 'SAMEORIGIN', postiz | 2|backend | 'referrer-policy': 'same-origin', postiz | 2|backend | 'cache-control': 'private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0', postiz | 2|backend | expires: 'Thu, 01 Jan 1970 00:00:01 GMT', postiz | 2|backend | vary: 'Accept-Encoding', postiz | 2|backend | 'access-control-allow-origin': '', postiz | 2|backend | 'access-control-expose-headers': 'X-CDN, X-CDN-Client-IP-Version, X-CDN-Proto, X-Cache, X-CDN-RCODE', postiz | 2|backend | 'timing-allow-origin': '', postiz | 2|backend | 'x-cdn': 'CFLR', postiz | 2|backend | 'x-content-type-options': 'nosniff', postiz | 2|backend | 'x-cdn-client-ip-version': 'IPV6', postiz | 2|backend | server: 'cloudflare', postiz | 2|backend | 'cf-ray': '99a56a018ebeabf7-YYZ', postiz | 2|backend | 'alt-svc': 'h3=":443"; ma=86400' postiz | 2|backend | },
postiz | 2|backend | _header: 'GET /dms/image/v2/redacted HTTP/1.1\r\n' + postiz | 2|backend | 'Accept: application/json, text/plain, /\r\n' + postiz | 2|backend | 'User-Agent: axios/1.12.2\r\n' + postiz | 2|backend | 'Accept-Encoding: gzip, compress, deflate, br\r\n' + postiz | 2|backend | 'Host: media.licdn.com\r\n' + postiz | 2|backend | 'Connection: keep-alive\r\n' + postiz | 2|backend | '\r\n', `
Found the fix!! Hidden in plain sight...
From the .env.example:
## Cloudflare is currently required to save things like social media avatars for accounts.
CLOUDFLARE_ACCOUNT_ID="your-account-id"
CLOUDFLARE_ACCESS_KEY="your-access-key"
CLOUDFLARE_SECRET_ACCESS_KEY="your-secret-access-key"
CLOUDFLARE_BUCKETNAME="your-bucket-name"
CLOUDFLARE_BUCKET_URL="https://your-bucket-url.r2.cloudflarestorage.com/"
CLOUDFLARE_REGION="auto"
So just setup an R2 bucket and you're good to go! (Quick tip, in the BUCKET_URL, use the url cloudflare provides without the trailing bucket name https://your-r2-id.r2.cloudflarestorage.com/bucket-name)
Don't forget to also change from local to cloudflare:
# Where will social media icons be saved - local or cloudflare.
STORAGE_PROVIDER="cloudflare"
All works now! Enjoy!
Found the fix!! Hidden in plain sight...
From the .env.example:
Cloudflare is currently required to save things like social media avatars for accounts.
Yes, thank you! That solved it for me too. For me this will work fine as workaround. It's a free solution.
That resolves the issue. Thanks @vertizio