// Copyright © 2023 Ory Corp // SPDX-License-Identifier: Apache-2.0 package oidc import ( "context" "fmt" "net/url" "slices" "github.com/ory/herodot" "github.com/pkg/errors" "golang.org/x/oauth2" "github.com/ory/x/stringsx" "github.com/slack-go/slack" ) var _ OAuth2Provider = (*ProviderSlack)(nil) type ProviderSlack struct { config *Configuration reg Dependencies } func NewProviderSlack( config *Configuration, reg Dependencies, ) Provider { return &ProviderSlack{ config: config, reg: reg, } } func (d *ProviderSlack) Config() *Configuration { return d.config } func (d *ProviderSlack) oauth2(ctx context.Context) *oauth2.Config { return &oauth2.Config{ ClientID: d.config.ClientID, ClientSecret: d.config.ClientSecret, Endpoint: oauth2.Endpoint{ // slack's oauth v2 does not implement the oauth2 standard so we use the old version. // to use v2 we would need to rename the request 'scope' field to 'user_scope'. AuthURL: "https://slack.com/oauth/authorize", TokenURL: slack.APIURL + "oauth.access", }, RedirectURL: d.config.Redir(d.reg.Config().OIDCRedirectURIBase(ctx)), Scopes: d.config.Scope, } } func (d *ProviderSlack) OAuth2(ctx context.Context) (*oauth2.Config, error) { return d.oauth2(ctx), nil } func (d *ProviderSlack) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { return []oauth2.AuthCodeOption{} } func (d *ProviderSlack) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) { grantedScopes := stringsx.Splitx(fmt.Sprintf("%s", exchange.Extra("scope")), ",") for _, check := range d.Config().Scope { if !slices.Contains(grantedScopes, check) { return nil, errors.WithStack(ErrScopeMissing()) } } api := slack.New(exchange.AccessToken) identity, err := api.GetUserIdentity() if err != nil { return nil, errors.WithStack(herodot.ErrUpstreamError().WithWrap(err).WithReasonf("%s", err)) } claims := &Claims{ Issuer: "https://slack.com/oauth/", Subject: identity.User.ID, Name: identity.User.Name, PreferredUsername: identity.User.Name, Nickname: identity.User.Name, Email: identity.User.Email, EmailVerified: true, Picture: identity.User.Image512, Team: identity.Team.ID, } return claims, nil }