trypost/config/services.php
Falconiere Barbosa 410eb9612e fix(linkedin): drop deprecated r_basicprofile from default scopes
Make r_basicprofile opt-in via LINKEDIN_EXTRA_SCOPES so self-hosted users
unblock by default and ops with legacy/enterprise products keep working.

Why
---
LinkedIn rejects OAuth authorize requests with a generic "Bummer,
something went wrong" page when an app asks for a scope it can't grant.
`r_basicprofile` is a legacy scope deprecated in 2018; new LinkedIn dev
apps don't have it, so every self-hosted user hits the rejection
immediately on `/connect/linkedin`.

The two products LinkedIn actually grants to standard apps today are:

- Sign In with LinkedIn using OpenID Connect → `openid profile email`
- Share on LinkedIn                          → `w_member_social`

That set is enough for the connect flow. The only piece of data
`r_basicprofile` was buying us is `/v2/me`'s `vanityName` (pretty
`linkedin.com/in/<slug>`). `fetchVanityName()` already handles HTTP
failure gracefully (returns null), and the only downstream consumer —
`LinkedInPagePublisher`'s post-URL builder — already falls back to a
numeric `linkedin.com/feed/update/<id>` URL when `$account->username`
is null.

Backward compatibility
----------------------
Ops with legacy or enterprise LinkedIn products approved on their dev
app (so they DO have `r_basicprofile`) can opt back in via env:

    LINKEDIN_EXTRA_SCOPES=r_basicprofile

`LinkedInController::resolveScopes()` merges this comma-separated list
into the default scope array. The connect flow's `Socialite::scopes()`
call then includes the legacy scope, preserving the pre-PR behaviour
end-to-end (including `vanityName` lookup).

Net effect for users without `r_basicprofile`:
- Connect flow works (was previously rejected by LinkedIn).
- Posts publish exactly the same way.
- Generated post URLs use the numeric form instead of the vanity slug.

Tests
-----
- `linkedin connect requests the default scope set when LINKEDIN_EXTRA_SCOPES is unset`
- `linkedin connect appends LINKEDIN_EXTRA_SCOPES to the default scope set`
- Existing `splits comma-separated approvedScopes` fixture updated to
  match the new default set.
2026-06-10 13:51:07 -03:00

147 lines
4.2 KiB
PHP

<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'postmark' => [
'key' => env('POSTMARK_API_KEY'),
],
'resend' => [
'key' => env('RESEND_API_KEY'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],
'linkedin' => [
'client_id' => env('LINKEDIN_CLIENT_ID'),
'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
'redirect' => env('LINKEDIN_CLIENT_REDIRECT'),
// Comma-separated list of OAuth scopes to request beyond the defaults
// (openid, profile, email, w_member_social). Useful for apps with
// legacy or enterprise products approved — e.g. set
// `LINKEDIN_EXTRA_SCOPES=r_basicprofile` to re-enable vanityName
// lookup via /v2/me.
'extra_scopes' => env('LINKEDIN_EXTRA_SCOPES'),
],
'linkedin-openid' => [
'client_id' => env('LINKEDIN_CLIENT_ID'),
'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
'redirect' => env('LINKEDIN_CLIENT_REDIRECT'),
'redirect_page' => env('LINKEDIN_PAGE_CLIENT_REDIRECT'),
],
'x' => [
'client_id' => env('X_CLIENT_ID'),
'client_secret' => env('X_CLIENT_SECRET'),
'redirect' => env('X_CLIENT_REDIRECT'),
],
'tiktok' => [
'client_id' => env('TIKTOK_CLIENT_ID'),
'client_secret' => env('TIKTOK_CLIENT_SECRET'),
'redirect' => env('TIKTOK_CLIENT_REDIRECT'),
],
// Google OAuth (used for YouTube)
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_CLIENT_REDIRECT'),
],
// Google OAuth (used for login/signup)
'google-auth' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_AUTH_CALLBACK'),
],
// GitHub OAuth (used for login/signup)
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_AUTH_CALLBACK'),
],
// Facebook Pages
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_CLIENT_REDIRECT'),
],
// Instagram
'instagram' => [
'client_id' => env('INSTAGRAM_CLIENT_ID'),
'client_secret' => env('INSTAGRAM_CLIENT_SECRET'),
'redirect' => env('INSTAGRAM_CLIENT_REDIRECT'),
],
// Threads
'threads' => [
'client_id' => env('THREADS_CLIENT_ID'),
'client_secret' => env('THREADS_CLIENT_SECRET'),
'redirect' => env('THREADS_CLIENT_REDIRECT'),
],
// Pinterest
'pinterest' => [
'client_id' => env('PINTEREST_CLIENT_ID'),
'client_secret' => env('PINTEREST_CLIENT_SECRET'),
'redirect' => env('PINTEREST_CLIENT_REDIRECT'),
],
'gtm' => [
'id' => env('GTM_ID'),
],
'posthog' => [
'enabled' => (bool) env('POSTHOG_ENABLED', false),
'api_key' => env('POSTHOG_API_KEY'),
'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'),
],
'unsplash' => [
'access_key' => env('UNSPLASH_ACCESS_KEY'),
'secret_key' => env('UNSPLASH_SECRET_KEY'),
],
'giphy' => [
'api_key' => env('GIPHY_API_KEY'),
],
'openai' => [
'api_key' => env('OPENAI_API_KEY'),
],
'gemini' => [
'api_key' => env('GEMINI_API_KEY'),
],
];