Skip to content

Add OpenID Connect Support for Slack Apps#1381

Merged
atymic merged 1 commit intoSocialiteProviders:masterfrom
maartenpaauw:feat/slack-optional-openid-support
Aug 26, 2025
Merged

Add OpenID Connect Support for Slack Apps#1381
atymic merged 1 commit intoSocialiteProviders:masterfrom
maartenpaauw:feat/slack-optional-openid-support

Conversation

@maartenpaauw
Copy link
Copy Markdown
Contributor

Overview

This PR adds automatic OpenID Connect support to the Slack provider to ensure compatibility with Slack's new marketplace requirements while maintaining full backward compatibility with existing implementations.

Problem

Slack has updated their marketplace approval process and new Slack apps will not be approved if they use the legacy identity.* scopes (identity.basic, identity.email, identity.team, identity.avatar). Instead, Slack now requires apps to use OpenID Connect with the scopes openid, email, profile and corresponding OpenID Connect endpoints.

Solution

This implementation automatically detects when OpenID Connect scopes are being used and switches to the appropriate endpoints:

Endpoint Mapping

When using OpenID Connect scopes (openid, email, profile) without bot scopes:

  • Authorization: https://slack.com/openid/connect/authorize (instead of https://slack.com/oauth/v2/authorize)
  • Token Exchange: https://slack.com/api/openid.connect.token (instead of https://slack.com/api/oauth.v2.access)
  • User Information: https://slack.com/api/openid.connect.userInfo (instead of https://slack.com/api/users.identity)

Detection Logic

OpenID Connect mode is automatically enabled when:

  1. ✅ OpenID scopes are present (openid, email, profile)
  2. ✅ No legacy identity scopes are mixed in
  3. ✅ No bot scopes are configured (OpenID Connect doesn't support bot tokens)

Changes Made

Before (Legacy Implementation)

// Fixed endpoints
getAuthUrl() -> 'https://slack.com/oauth/v2/authorize'
getTokenUrl() -> 'https://slack.com/api/oauth.v2.access'
getUserByToken() -> 'https://slack.com/api/users.identity'

// Fixed token extraction
$token = Arr::get($response, 'authed_user.access_token');

// Fixed user mapping from legacy API structure
'id' => Arr::get($user, 'user.id')

After (Dynamic Implementation)

// Dynamic endpoints based on scopes
getAuthUrl() -> shouldUseOpenIdConnect() ? OpenID : OAuth2
getTokenUrl() -> shouldUseOpenIdConnect() ? OpenID : OAuth2  
getUserByToken() -> usesOpenIdScopes() ? OpenID : legacy

// Dynamic token extraction
$token = shouldUseOpenIdConnect() ? 'access_token' : 'authed_user.access_token'

// Dynamic user mapping for both API formats
OpenID: 'id' => Arr::get($user, 'sub')
Legacy: 'id' => Arr::get($user, 'user.id')

Key Implementation Details

  1. Dynamic Endpoint Selection:

    • getAuthUrl() and getTokenUrl() now route based on shouldUseOpenIdConnect()
    • getUserByToken() routes based on usesOpenIdScopes()
  2. Smart Token Extraction:

    • OpenID Connect: extracts access_token directly
    • Legacy OAuth2: extracts authed_user.access_token
  3. Dual User Mapping:

    • OpenID Connect: maps from sub, name, email, picture, https://slack.com/team_id
    • Legacy: maps from user.id, user.name, user.email, user.image_512, team.id
  4. Enhanced Field Handling:

    • OpenID Connect: uses single scope field with space separator
    • Legacy OAuth2: uses separate user_scope and scope fields

New Methods Added

  • shouldUseOpenIdConnect(): Returns true when using OpenID scopes AND no bot scopes
  • usesOpenIdScopes(): Detects OpenID scopes without legacy identity scopes

Usage Examples

✅ Oauth Approach (Unchanged)

// Existing code continues to work exactly as before
Socialite::driver('slack')
    ->scopes(['identity.basic', 'identity.email', 'identity.team', 'identity.avatar'])
    ->redirect();

✅ New OpenID Connect Approach

// Automatically uses OpenID Connect endpoints
Socialite::driver('slack')
    ->scopes(['openid', 'email', 'profile'])
    ->redirect();

✅ Bot and User Scopes (Uses Oauth + Openid)

// When bot scopes present, automatically uses OAuth2
Socialite::driver('slack')
    ->scopes(['openid', 'email', 'profile']
    ->botScopes(['chat:write'])
    ->redirect();

This implementation ensures seamless compatibility with Slack's marketplace requirements while preserving all existing functionality.

@maartenpaauw maartenpaauw force-pushed the feat/slack-optional-openid-support branch from 27debc4 to 2e21f8e Compare August 21, 2025 07:01
@atymic
Copy link
Copy Markdown
Member

atymic commented Aug 22, 2025

Excellent work :)
This doesn't need a major version as it detects the scopes, right?

@maartenpaauw
Copy link
Copy Markdown
Contributor Author

maartenpaauw commented Aug 25, 2025

@atymic You are right. In my opinion this does not need a major release, because it uses the current Slack auth + API endpoints when using identity scopes and non of the OpenID scopes. When using the new OpenID scopes, it uses the new API endpoint. Only the user array key might differ with this change, because an entire new API endpoint is called. The current version holds both user and team.

@atymic atymic merged commit c2819fa into SocialiteProviders:master Aug 26, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants