Files
remark42/backend/vendor/github.com/slack-go/slack/oauth.go
T
Dmitry VerkhoturovandUmputun 80c12a3f10 chore(deps): update Go modules
Bump Go dependencies in both backend/ and backend/_example/memory_store.

Notable updates:
- github.com/go-pkgz/lgr v0.12.1 -> v0.12.3
- github.com/klauspost/compress v1.18.2 -> v1.18.5
- github.com/PuerkitoBio/goquery v1.11.0 -> v1.12.0
- github.com/montanaflynn/stats v0.7.1 -> v0.9.0
- github.com/redis/go-redis/v9 v9.17.2 -> v9.18.0
- github.com/slack-go/slack v0.17.3 -> v0.21.1
- go.mongodb.org/mongo-driver v1.17.6 -> v1.17.9
- golang.org/x/crypto v0.48.0 -> v0.50.0
- golang.org/x/net v0.49.0 -> v0.53.0
- golang.org/x/image v0.36.0 -> v0.39.0
- golang.org/x/sys v0.41.0 -> v0.43.0
- golang.org/x/{oauth2,sync,text} minor bumps

Key markdown/sanitisation libs (bluemonday v1.0.27,
alecthomas/chroma/v2 v2.23.1, russross/blackfriday/v2 v2.1.0,
Depado/bfchroma/v2 v2.0.0) are already at the latest available
versions and were not bumped.

Verified the Chroma span-class allowlist regex in
backend/app/store/comment.go:128-131 is still fully in sync with
chroma/v2 types.go StandardTypes map (86 classes, byte-equal after
sorting). The inline comment references commit c263f6f which is
stale (Chroma is at v2 now), but the class list content is current.

Ran `go mod tidy` + `go mod vendor` + full race test suite on both
modules. All green. Added a reminder in CLAUDE.md that updating
backend/ Go modules also requires `go mod tidy` in
backend/_example/memory_store since the example module uses a
local replace directive and inherits indirect deps from the main
module.
2026-04-12 11:52:57 -05:00

289 lines
12 KiB
Go

package slack
import (
"context"
"net/url"
)
// OAuthResponseIncomingWebhook ...
type OAuthResponseIncomingWebhook struct {
URL string `json:"url"`
Channel string `json:"channel"`
ChannelID string `json:"channel_id,omitempty"`
ConfigurationURL string `json:"configuration_url"`
}
// OAuthResponseBot ...
type OAuthResponseBot struct {
BotUserID string `json:"bot_user_id"`
BotAccessToken string `json:"bot_access_token"`
}
// OAuthResponse ...
type OAuthResponse struct {
AccessToken string `json:"access_token"`
Scope string `json:"scope"`
TeamName string `json:"team_name"`
TeamID string `json:"team_id"`
IncomingWebhook OAuthResponseIncomingWebhook `json:"incoming_webhook"`
Bot OAuthResponseBot `json:"bot"`
UserID string `json:"user_id,omitempty"`
SlackResponse
}
// OAuthV2Response ...
type OAuthV2Response struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
BotUserID string `json:"bot_user_id"`
AppID string `json:"app_id"`
Team OAuthV2ResponseTeam `json:"team"`
IncomingWebhook OAuthResponseIncomingWebhook `json:"incoming_webhook"`
Enterprise OAuthV2ResponseEnterprise `json:"enterprise"`
IsEnterpriseInstall bool `json:"is_enterprise_install"`
AuthedUser OAuthV2ResponseAuthedUser `json:"authed_user"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
SlackResponse
}
// OAuthV2ResponseTeam ...
type OAuthV2ResponseTeam struct {
ID string `json:"id"`
Name string `json:"name"`
}
// OAuthV2ResponseEnterprise ...
type OAuthV2ResponseEnterprise struct {
ID string `json:"id"`
Name string `json:"name"`
}
// OAuthV2ResponseAuthedUser ...
type OAuthV2ResponseAuthedUser struct {
ID string `json:"id"`
Scope string `json:"scope"`
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
}
// OpenIDConnectResponse ...
type OpenIDConnectResponse struct {
Ok bool `json:"ok"`
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
IdToken string `json:"id_token"`
SlackResponse
}
type oauthConfig struct {
apiURL string
}
// OAuthOption configures package-level OAuth functions.
type OAuthOption func(*oauthConfig)
// OAuthOptionAPIURL overrides the default Slack API URL. Useful for testing.
func OAuthOptionAPIURL(url string) OAuthOption {
return func(c *oauthConfig) { c.apiURL = url }
}
func resolveOAuthAPIURL(opts []OAuthOption) string {
c := oauthConfig{apiURL: APIURL}
for _, o := range opts {
o(&c)
}
return c.apiURL
}
// GetOAuthToken retrieves an AccessToken.
// For more details, see GetOAuthTokenContext documentation.
func GetOAuthToken(client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (accessToken string, scope string, err error) {
return GetOAuthTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI, opts...)
}
// GetOAuthTokenContext retrieves an AccessToken with a custom context.
// For more details, see GetOAuthResponseContext documentation.
func GetOAuthTokenContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (accessToken string, scope string, err error) {
response, err := GetOAuthResponseContext(ctx, client, clientID, clientSecret, code, redirectURI, opts...)
if err != nil {
return "", "", err
}
return response.AccessToken, response.Scope, nil
}
// GetBotOAuthToken retrieves top-level and bot AccessToken - https://api.slack.com/legacy/oauth#bot_user_access_tokens
// For more details, see GetBotOAuthTokenContext documentation.
func GetBotOAuthToken(client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (accessToken string, scope string, bot OAuthResponseBot, err error) {
return GetBotOAuthTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI, opts...)
}
// GetBotOAuthTokenContext retrieves top-level and bot AccessToken with a custom context.
// For more details, see GetOAuthResponseContext documentation.
func GetBotOAuthTokenContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (accessToken string, scope string, bot OAuthResponseBot, err error) {
response, err := GetOAuthResponseContext(ctx, client, clientID, clientSecret, code, redirectURI, opts...)
if err != nil {
return "", "", OAuthResponseBot{}, err
}
return response.AccessToken, response.Scope, response.Bot, nil
}
// GetOAuthResponse retrieves OAuth response.
// For more details, see GetOAuthResponseContext documentation.
func GetOAuthResponse(client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OAuthResponse, err error) {
return GetOAuthResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI, opts...)
}
// GetOAuthResponseContext retrieves OAuth response with custom context.
// Slack API docs: https://api.slack.com/methods/oauth.access
func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OAuthResponse, err error) {
values := url.Values{
"client_id": {clientID},
"client_secret": {clientSecret},
"code": {code},
"redirect_uri": {redirectURI},
}
response := &OAuthResponse{}
if _, err = postForm(ctx, client, resolveOAuthAPIURL(opts)+"oauth.access", values, response, discard{}); err != nil {
return nil, err
}
return response, response.Err()
}
// GetOAuthV2Response gets a V2 OAuth access token response.
// For more details, see GetOAuthV2ResponseContext documentation.
func GetOAuthV2Response(client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OAuthV2Response, err error) {
return GetOAuthV2ResponseContext(context.Background(), client, clientID, clientSecret, code, redirectURI, opts...)
}
// GetOAuthV2ResponseContext with a context, gets a V2 OAuth access token response.
// Slack API docs: https://api.slack.com/methods/oauth.v2.access
func GetOAuthV2ResponseContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OAuthV2Response, err error) {
values := url.Values{
"client_id": {clientID},
"client_secret": {clientSecret},
"code": {code},
"redirect_uri": {redirectURI},
}
response := &OAuthV2Response{}
if _, err = postForm(ctx, client, resolveOAuthAPIURL(opts)+"oauth.v2.access", values, response, discard{}); err != nil {
return nil, err
}
return response, response.Err()
}
// RefreshOAuthV2Token with a context, gets a V2 OAuth access token response.
// For more details, see RefreshOAuthV2TokenContext documentation.
func RefreshOAuthV2Token(client httpClient, clientID, clientSecret, refreshToken string, opts ...OAuthOption) (resp *OAuthV2Response, err error) {
return RefreshOAuthV2TokenContext(context.Background(), client, clientID, clientSecret, refreshToken, opts...)
}
// RefreshOAuthV2TokenContext with a context, gets a V2 OAuth access token response.
// Slack API docs: https://api.slack.com/methods/oauth.v2.access
func RefreshOAuthV2TokenContext(ctx context.Context, client httpClient, clientID, clientSecret, refreshToken string, opts ...OAuthOption) (resp *OAuthV2Response, err error) {
values := url.Values{
"client_id": {clientID},
"client_secret": {clientSecret},
"refresh_token": {refreshToken},
"grant_type": {"refresh_token"},
}
response := &OAuthV2Response{}
if _, err = postForm(ctx, client, resolveOAuthAPIURL(opts)+"oauth.v2.access", values, response, discard{}); err != nil {
return nil, err
}
return response, response.Err()
}
// OpenIDConnectUserInfoResponse contains the response from openid.connect.userInfo.
//
// Some of the fields in the response to this method are preceded with https://slack.com/.
// These fields are Slack-specific, and they're from the perspective of Slack.
type OpenIDConnectUserInfoResponse struct {
Ok bool `json:"ok"`
Sub string `json:"sub"`
UserID string `json:"https://slack.com/user_id"`
TeamID string `json:"https://slack.com/team_id"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
DateEmailVerified int64 `json:"date_email_verified"`
Name string `json:"name"`
Picture string `json:"picture"`
GivenName string `json:"given_name"`
FamilyName string `json:"family_name"`
Locale string `json:"locale"`
TeamName string `json:"https://slack.com/team_name"`
TeamDomain string `json:"https://slack.com/team_domain"`
TeamImage34 string `json:"https://slack.com/team_image_34"`
TeamImage44 string `json:"https://slack.com/team_image_44"`
TeamImage68 string `json:"https://slack.com/team_image_68"`
TeamImage88 string `json:"https://slack.com/team_image_88"`
TeamImage102 string `json:"https://slack.com/team_image_102"`
TeamImage132 string `json:"https://slack.com/team_image_132"`
TeamImage230 string `json:"https://slack.com/team_image_230"`
// `TeamImageDefault` indicates whether the image is a default one (true), or someone
// uploaded their own (false).
TeamImageDefault bool `json:"https://slack.com/team_image_default"`
UserImage24 string `json:"https://slack.com/user_image_24"`
UserImage32 string `json:"https://slack.com/user_image_32"`
UserImage48 string `json:"https://slack.com/user_image_48"`
UserImage72 string `json:"https://slack.com/user_image_72"`
UserImage192 string `json:"https://slack.com/user_image_192"`
UserImage512 string `json:"https://slack.com/user_image_512"`
UserImage1024 string `json:"https://slack.com/user_image_1024"`
UserImageOriginal string `json:"https://slack.com/user_image_original"`
SlackResponse
}
// GetOpenIDConnectUserInfo returns the user info for the token.
// For more details, see GetOpenIDConnectUserInfoContext documentation.
func (api *Client) GetOpenIDConnectUserInfo() (*OpenIDConnectUserInfoResponse, error) {
return api.GetOpenIDConnectUserInfoContext(context.Background())
}
// GetOpenIDConnectUserInfoContext returns identity information about the user associated with the token.
// Slack API docs: https://docs.slack.dev/reference/methods/openid.connect.userInfo
func (api *Client) GetOpenIDConnectUserInfoContext(ctx context.Context) (*OpenIDConnectUserInfoResponse, error) {
values := url.Values{
"token": {api.token},
}
response := &OpenIDConnectUserInfoResponse{}
err := api.postMethod(ctx, "openid.connect.userInfo", values, response)
if err != nil {
return nil, err
}
return response, response.Err()
}
// GetOpenIDConnectToken exchanges a temporary OAuth verifier code for an access token for Sign in with Slack.
// For more details, see GetOpenIDConnectTokenContext documentation.
func GetOpenIDConnectToken(client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OpenIDConnectResponse, err error) {
return GetOpenIDConnectTokenContext(context.Background(), client, clientID, clientSecret, code, redirectURI, opts...)
}
// GetOpenIDConnectTokenContext with a context, gets an access token for Sign in with Slack.
// Slack API docs: https://api.slack.com/methods/openid.connect.token
func GetOpenIDConnectTokenContext(ctx context.Context, client httpClient, clientID, clientSecret, code, redirectURI string, opts ...OAuthOption) (resp *OpenIDConnectResponse, err error) {
values := url.Values{
"client_id": {clientID},
"client_secret": {clientSecret},
"code": {code},
"redirect_uri": {redirectURI},
}
response := &OpenIDConnectResponse{}
if _, err = postForm(ctx, client, resolveOAuthAPIURL(opts)+"openid.connect.token", values, response, discard{}); err != nil {
return nil, err
}
return response, response.Err()
}