config.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2024 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package auth0
  5. import (
  6. "context"
  7. "encoding/json"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "net/url"
  12. "strings"
  13. "golang.org/x/oauth2"
  14. )
  15. // Config contains configuration for Auth0 authentication provider.
  16. type Config struct {
  17. // Domain is the Auth0 domain (e.g., "your-domain.auth0.com")
  18. Domain string
  19. // ClientID is the Auth0 application client ID
  20. ClientID string
  21. // ClientSecret is the Auth0 application client secret
  22. ClientSecret string
  23. // CallbackURL is the callback URL for OAuth2 flow
  24. CallbackURL string
  25. // Scopes are the OAuth2 scopes to request
  26. Scopes []string
  27. }
  28. // OAuth2Config returns the OAuth2 configuration for Auth0
  29. func (c *Config) OAuth2Config() *oauth2.Config {
  30. return &oauth2.Config{
  31. ClientID: c.ClientID,
  32. ClientSecret: c.ClientSecret,
  33. RedirectURL: c.CallbackURL,
  34. Scopes: c.Scopes,
  35. Endpoint: oauth2.Endpoint{
  36. AuthURL: fmt.Sprintf("https://%s/authorize", c.Domain),
  37. TokenURL: fmt.Sprintf("https://%s/oauth/token", c.Domain),
  38. },
  39. }
  40. }
  41. // AuthCodeURL generates the Auth0 authorization URL
  42. func (c *Config) AuthCodeURL(state string) string {
  43. config := c.OAuth2Config()
  44. return config.AuthCodeURL(state, oauth2.AccessTypeOffline)
  45. }
  46. // ExchangeCode exchanges authorization code for access token
  47. func (c *Config) ExchangeCode(ctx context.Context, code string) (*oauth2.Token, error) {
  48. config := c.OAuth2Config()
  49. return config.Exchange(ctx, code)
  50. }
  51. // UserInfo represents Auth0 user information
  52. type UserInfo struct {
  53. Sub string `json:"sub"`
  54. Name string `json:"name"`
  55. GivenName string `json:"given_name"`
  56. FamilyName string `json:"family_name"`
  57. Picture string `json:"picture"`
  58. Email string `json:"email"`
  59. EmailVerified bool `json:"email_verified"`
  60. Locale string `json:"locale"`
  61. UpdatedAt string `json:"updated_at"`
  62. }
  63. // GetUserInfo retrieves user information from Auth0 using access token
  64. func (c *Config) GetUserInfo(ctx context.Context, token *oauth2.Token) (*UserInfo, error) {
  65. client := c.OAuth2Config().Client(ctx, token)
  66. resp, err := client.Get(fmt.Sprintf("https://%s/userinfo", c.Domain))
  67. if err != nil {
  68. return nil, fmt.Errorf("failed to get user info: %w", err)
  69. }
  70. defer resp.Body.Close()
  71. if resp.StatusCode != http.StatusOK {
  72. body, _ := io.ReadAll(resp.Body)
  73. return nil, fmt.Errorf("failed to get user info: status %d, body: %s", resp.StatusCode, string(body))
  74. }
  75. var userInfo UserInfo
  76. if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
  77. return nil, fmt.Errorf("failed to decode user info: %w", err)
  78. }
  79. return &userInfo, nil
  80. }
  81. // ValidateConfig validates the Auth0 configuration
  82. func (c *Config) ValidateConfig() error {
  83. if c.Domain == "" {
  84. return fmt.Errorf("Auth0 domain is required")
  85. }
  86. if c.ClientID == "" {
  87. return fmt.Errorf("Auth0 client ID is required")
  88. }
  89. if c.ClientSecret == "" {
  90. return fmt.Errorf("Auth0 client secret is required")
  91. }
  92. if c.CallbackURL == "" {
  93. return fmt.Errorf("Auth0 callback URL is required")
  94. }
  95. // Validate domain format
  96. if !strings.HasSuffix(c.Domain, ".auth0.com") && !strings.Contains(c.Domain, ".") {
  97. return fmt.Errorf("invalid Auth0 domain format")
  98. }
  99. // Validate callback URL format
  100. if _, err := url.Parse(c.CallbackURL); err != nil {
  101. return fmt.Errorf("invalid callback URL: %w", err)
  102. }
  103. return nil
  104. }
  105. // DefaultScopes returns the default OAuth2 scopes for Auth0
  106. func DefaultScopes() []string {
  107. return []string{"openid", "profile", "email"}
  108. }