Files
upstream-mirror c60cc7ca75
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:19:12 +05:00

118 lines
3.2 KiB
Go

// Copyright © 2022 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package oidc
import (
"context"
"encoding/json"
"net/url"
"github.com/hashicorp/go-retryablehttp"
"github.com/pkg/errors"
"golang.org/x/oauth2"
"github.com/ory/herodot"
"github.com/ory/x/httpx"
)
var _ OAuth2Provider = (*ProviderLark)(nil)
type ProviderLark struct {
*ProviderGenericOIDC
}
var (
larkAuthEndpoint = oauth2.Endpoint{
AuthURL: "https://passport.feishu.cn/suite/passport/oauth/authorize",
TokenURL: "https://passport.feishu.cn/suite/passport/oauth/token",
AuthStyle: oauth2.AuthStyleInParams,
}
larkUserEndpoint = "https://passport.feishu.cn/suite/passport/oauth/userinfo"
)
func NewProviderLark(
config *Configuration,
reg Dependencies,
) Provider {
return &ProviderLark{
&ProviderGenericOIDC{
config: config,
reg: reg,
},
}
}
func (pl *ProviderLark) Config() *Configuration {
return pl.config
}
func (pl *ProviderLark) OAuth2(ctx context.Context) (*oauth2.Config, error) {
return &oauth2.Config{
ClientID: pl.config.ClientID,
ClientSecret: pl.config.ClientSecret,
Endpoint: larkAuthEndpoint,
// Lark uses fixed scope that can not be configured in runtime
Scopes: pl.config.Scope,
RedirectURL: pl.config.Redir(pl.reg.Config().OIDCRedirectURIBase(ctx)),
}, nil
}
func (pl *ProviderLark) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) {
// larkClaim is defined in the https://open.feishu.cn/document/common-capabilities/sso/api/get-user-info
type larkClaim struct {
Sub string `json:"sub"`
Name string `json:"name"`
Picture string `json:"picture"`
OpenID string `json:"open_id"`
UnionID string `json:"union_id"`
EnName string `json:"en_name"`
TenantKey string `json:"tenant_key"`
AvatarURL string `json:"avatar_url"`
AvatarThumb string `json:"avatar_thumb"`
AvatarMiddle string `json:"avatar_middle"`
AvatarBig string `json:"avatar_big"`
Email string `json:"email"`
UserID string `json:"user_id"`
Mobile string `json:"mobile"`
}
var (
client = pl.reg.HTTPClient(ctx, httpx.ResilientClientDisallowInternalIPs())
user larkClaim
)
req, err := retryablehttp.NewRequest("GET", larkUserEndpoint, nil)
if err != nil {
return nil, errors.WithStack(herodot.ErrInternalServerError().WithWrap(err).WithReasonf("%s", err))
}
exchange.SetAuthHeader(req.Request)
res, err := client.Do(req)
if err != nil {
return nil, errors.WithStack(herodot.ErrUpstreamError().WithWrap(err).WithReasonf("%s", err))
}
defer func() { _ = res.Body.Close() }()
if err := logUpstreamError(pl.reg.Logger(), res); err != nil {
return nil, err
}
if err := json.NewDecoder(res.Body).Decode(&user); err != nil {
return nil, errors.WithStack(herodot.ErrUpstreamError().WithWrap(err).WithReasonf("%s", err))
}
return &Claims{
Issuer: larkUserEndpoint,
Subject: user.OpenID,
Name: user.Name,
Nickname: user.Name,
Picture: user.AvatarURL,
Email: user.Email,
PhoneNumber: user.Mobile,
}, nil
}
func (pl *ProviderLark) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption {
return []oauth2.AuthCodeOption{}
}