forked from supabase/auth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for Slack OAuth V2 (supabase#1591)
## What kind of change does this PR introduce? - Updates the Slack OAuth provider with the new Sign In With Slack V2. - Creates a test for Slack, improving test coverage - Moves the old Slack provider to slack_legacy. Some users might still rely on this provider after the creation of legacy apps is disallowed on June 4th. ## What is the current behavior? Fixes supabase#1294 Current behavior uses the original Slack OAuth V1 which is sunsetting June 4th according to [the changelog](https://api.slack.com/changelog/2024-04-discontinuing-new-creation-of-classic-slack-apps-and-custom-bots) ## What is the new behavior? New behavior now leverages the new [Sign In With Slack](https://api.slack.com/authentication/sign-in-with-slack) (SIWS) on OAuth V2 for Slack authentication. ## Additional context A ticket should be created for ending support on slack_legacy. --------- Co-authored-by: Kang Ming <kang.ming1996@gmail.com>
- Loading branch information
Showing
9 changed files
with
150 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package api | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"net/url" | ||
|
||
jwt "github.com/golang-jwt/jwt" | ||
) | ||
|
||
func (ts *ExternalTestSuite) TestSignupExternalSlackOIDC() { | ||
req := httptest.NewRequest(http.MethodGet, "http://localhost/authorize?provider=slack_oidc", nil) | ||
w := httptest.NewRecorder() | ||
ts.API.handler.ServeHTTP(w, req) | ||
ts.Require().Equal(http.StatusFound, w.Code) | ||
u, err := url.Parse(w.Header().Get("Location")) | ||
ts.Require().NoError(err, "redirect url parse failed") | ||
q := u.Query() | ||
ts.Equal(ts.Config.External.Slack.RedirectURI, q.Get("redirect_uri")) | ||
ts.Equal(ts.Config.External.Slack.ClientID, []string{q.Get("client_id")}) | ||
ts.Equal("code", q.Get("response_type")) | ||
ts.Equal("profile email openid", q.Get("scope")) | ||
|
||
claims := ExternalProviderClaims{} | ||
p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}} | ||
_, err = p.ParseWithClaims(q.Get("state"), &claims, func(token *jwt.Token) (interface{}, error) { | ||
return []byte(ts.Config.JWT.Secret), nil | ||
}) | ||
ts.Require().NoError(err) | ||
|
||
ts.Equal("slack_oidc", claims.Provider) | ||
ts.Equal(ts.Config.SiteURL, claims.SiteURL) | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
"github.com/supabase/auth/internal/conf" | ||
"golang.org/x/oauth2" | ||
) | ||
|
||
const defaultSlackOIDCApiBase = "slack.com" | ||
|
||
type slackOIDCProvider struct { | ||
*oauth2.Config | ||
APIPath string | ||
} | ||
|
||
type slackOIDCUser struct { | ||
ID string `json:"https://slack.com/user_id"` | ||
TeamID string `json:"https://slack.com/team_id"` | ||
Email string `json:"email"` | ||
EmailVerified bool `json:"email_verified"` | ||
Name string `json:"name"` | ||
AvatarURL string `json:"picture"` | ||
} | ||
|
||
// NewSlackOIDCProvider creates a Slack account provider with Sign in with Slack. | ||
func NewSlackOIDCProvider(ext conf.OAuthProviderConfiguration, scopes string) (OAuthProvider, error) { | ||
if err := ext.ValidateOAuth(); err != nil { | ||
return nil, err | ||
} | ||
|
||
apiPath := chooseHost(ext.URL, defaultSlackOIDCApiBase) + "/api" | ||
authPath := chooseHost(ext.URL, defaultSlackOIDCApiBase) + "/openid" | ||
|
||
// these are required scopes for slack's OIDC flow | ||
// see https://api.slack.com/authentication/sign-in-with-slack#implementation | ||
oauthScopes := []string{ | ||
"profile", | ||
"email", | ||
"openid", | ||
} | ||
|
||
if scopes != "" { | ||
oauthScopes = append(oauthScopes, strings.Split(scopes, ",")...) | ||
} | ||
|
||
return &slackOIDCProvider{ | ||
Config: &oauth2.Config{ | ||
ClientID: ext.ClientID[0], | ||
ClientSecret: ext.Secret, | ||
Endpoint: oauth2.Endpoint{ | ||
AuthURL: authPath + "/connect/authorize", | ||
TokenURL: apiPath + "/openid.connect.token", | ||
}, | ||
Scopes: oauthScopes, | ||
RedirectURL: ext.RedirectURI, | ||
}, | ||
APIPath: apiPath, | ||
}, nil | ||
} | ||
|
||
func (g slackOIDCProvider) GetOAuthToken(code string) (*oauth2.Token, error) { | ||
return g.Exchange(context.Background(), code) | ||
} | ||
|
||
func (g slackOIDCProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) { | ||
var u slackOIDCUser | ||
if err := makeRequest(ctx, tok, g.Config, g.APIPath+"/openid.connect.userInfo", &u); err != nil { | ||
return nil, err | ||
} | ||
|
||
data := &UserProvidedData{} | ||
if u.Email != "" { | ||
data.Emails = []Email{{ | ||
Email: u.Email, | ||
// email_verified is returned as part of the response | ||
// see: https://api.slack.com/authentication/sign-in-with-slack#response | ||
Verified: u.EmailVerified, | ||
Primary: true, | ||
}} | ||
} | ||
|
||
data.Metadata = &Claims{ | ||
Issuer: g.APIPath, | ||
Subject: u.ID, | ||
Name: u.Name, | ||
Picture: u.AvatarURL, | ||
CustomClaims: map[string]interface{}{ | ||
"https://slack.com/team_id": u.TeamID, | ||
}, | ||
|
||
// To be deprecated | ||
AvatarURL: u.AvatarURL, | ||
FullName: u.Name, | ||
ProviderId: u.ID, | ||
} | ||
return data, nil | ||
} |
This file contains 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
This file contains 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
This file contains 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