fix(linkedin,pinterest): split CSV/space-joined OAuth scopes before saving#35
Merged
Conversation
…aving LinkedIn and Pinterest's OAuth providers return the granted scope list joined by comma (LinkedIn) or space-in-one-element (Pinterest), but Socialite's scope splitter doesn't match either, so 'approvedScopes' lands as a single-element array containing the whole list: LinkedIn: ['email,openid,profile,r_basicprofile,w_member_social'] Pinterest: ['boards:read boards:write pins:read pins:write user_accounts:read'] That breaks the publish-time scope check in PublishToSocialPlatform (array_diff does exact string compare), surfacing as 'Missing permissions: w_member_social. Please reconnect your account' even though the scopes were actually granted at the provider. Fix is inline at each callback — re-split before saving. Each provider has its own quirk (LinkedIn = comma, Pinterest = space), so each controller handles its own separator. Tests added: callback splits the joined approvedScopes into individual tokens for both providers.
c87497d to
49ccfe8
Compare
Adds an explicit test asserting that when a workspace has multiple LinkedIn users (e.g., the owner plus a client teammate), syncing tokens from one user's accounts never touches accounts admin'd by a different LinkedIn user — even though all live in the same workspace. The behavior is already correct by virtue of the `admin_user_id` / `platform_user_id` match in the synchronizer's query, but the property is now part of the test contract instead of emergent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Users connecting LinkedIn (and Pinterest) and posting some time later were hitting:
```
Missing permissions: w_member_social. Please reconnect your account.
```
…even though the LinkedIn account actually had the scope granted, and the daily `social:check-connections` reported the account as healthy.
Root cause
LinkedIn returns the granted `scope` field comma-separated and Pinterest returns it space-separated, but Socialite's scope splitter for each provider doesn't match what they actually return. The net effect: `approvedScopes` is saved as a single-element array containing the entire list as one string:
```
LinkedIn: ['email,openid,profile,r_basicprofile,w_member_social']
Pinterest: ['boards:read boards:write pins:read pins:write user_accounts:read']
```
When `PublishToSocialPlatform` runs:
```php
array_diff(['w_member_social'], ['email,openid,profile,r_basicprofile,w_member_social'])
```
`array_diff` does exact string compare. `'w_member_social'` doesn't equal the CSV string, so it reports it as missing → publish blocked.
Confirmed by inspecting both DB rows and live OAuth response logs.
Fix
Inline re-split at each callback before saving. Provider-specific quirks stay in their own controllers — no shared helper, no centralized abstraction.
`LinkedInController::callback`:
```php
'scopes' => explode(',', implode(',', $socialUser->approvedScopes)),
```
`PinterestController::callback`:
```php
'scopes' => explode(' ', implode(' ', $socialUser->approvedScopes)),
```
The `implode + explode` pattern handles both possible shapes: a single-element CSV (today's bug) or already-split multi-element (future-proof if Socialite ever changes).
Not affected
Existing broken accounts in DB
Will be fixed manually via direct SQL (3 LinkedIn rows + 1 Pinterest row). No migration in this PR.
Test plan