diff --git a/BRANCH_ORGANIZATION.md b/BRANCH_ORGANIZATION.md
new file mode 100644
index 0000000..eecfdd5
--- /dev/null
+++ b/BRANCH_ORGANIZATION.md
@@ -0,0 +1,101 @@
+# OAuth2 库分支组织
+
+## 📋 分支说明
+
+这个项目使用功能分支来组织不同的 OAuth2 提供者实现,以保持代码整洁和功能分离。
+
+## 🌳 分支结构
+
+### 主分支
+- **`master`** - 稳定的主分支,包含经过测试的功能
+- 包含: 基础 OAuth2 框架和成熟的提供者(GitHub、Google 等)
+
+### 功能分支
+
+#### 🔐 Supabase 分支
+- **分支名**: `cursor/implement-supabase-authentication-86da`
+- **功能**: Supabase OAuth2 提供者
+- **状态**: ✅ 完成
+- **包含**:
+ - `supabase/supabase.go` - Supabase OAuth2 实现
+ - `supabase/README.md` - 详细文档
+ - `example/supabase/` - 完整示例应用
+
+#### 🔑 WebAuthn 分支
+- **分支名**: `feature/webauthn-support`
+- **功能**: WebAuthn 无密码认证
+- **状态**: ✅ 完成
+- **包含**:
+ - `webauthn/webauthn.go` - WebAuthn OAuth2 适配器
+ - `webauthn/user.go` - 用户和会话管理
+ - `webauthn/README.md` - 详细文档和使用指南
+ - `example/webauthn/` - 完整示例应用(中文界面)
+ - `webauthn/webauthn_test.go` - 单元测试
+
+## 🚀 特性对比
+
+| 功能 | Supabase 分支 | WebAuthn 分支 |
+|-----|-------------|-------------|
+| 认证方式 | 传统 OAuth2 | 无密码认证 |
+| 安全性 | 标准 OAuth2 | 生物识别 + 硬件密钥 |
+| 用户体验 | 传统登录流程 | 现代无密码体验 |
+| 浏览器要求 | 所有现代浏览器 | Chrome 67+, Firefox 60+, Safari 14+ |
+| 硬件要求 | 无特殊要求 | 需要支持 WebAuthn 的设备 |
+
+## 📦 如何使用
+
+### 切换到 Supabase 分支
+```bash
+git checkout cursor/implement-supabase-authentication-86da
+cd example/supabase
+go run main.go
+```
+
+### 切换到 WebAuthn 分支
+```bash
+git checkout feature/webauthn-support
+cd example/webauthn
+go run main.go
+```
+
+## 🔄 分支合并策略
+
+1. **功能分支 → master**: 当功能稳定且经过充分测试后
+2. **独立开发**: 各功能分支独立开发,避免冲突
+3. **向前兼容**: 新功能不影响现有功能
+
+## 📝 开发建议
+
+### Supabase 分支开发
+- 专注于 Supabase 特定功能和改进
+- 保持与 Supabase API 的同步
+- 增强错误处理和用户体验
+
+### WebAuthn 分支开发
+- 关注无密码认证的安全性和兼容性
+- 扩展支持更多浏览器和设备
+- 优化用户体验和错误处理
+
+## 🛡️ 安全考虑
+
+### Supabase 分支
+- ✅ HTTPS 要求
+- ✅ 标准 OAuth2 安全流程
+- ✅ 令牌安全存储
+
+### WebAuthn 分支
+- ✅ 生物识别验证
+- ✅ 硬件密钥支持
+- ✅ 防钓鱼攻击
+- ✅ 域名绑定验证
+
+## 📊 测试状态
+
+| 分支 | 编译状态 | 测试状态 | 示例运行 |
+|-----|---------|---------|---------|
+| Supabase | ✅ 通过 | ⚠️ 需要测试 | ✅ 正常 |
+| WebAuthn | ✅ 通过 | ✅ 全部通过 | ✅ 正常 |
+
+---
+
+**💡 提示**: 这种分支组织确保了功能的独立性,便于维护和合并,同时避免了不同功能之间的冲突。
\ No newline at end of file
diff --git a/README.md b/README.md
index 0cb2564..fc6e80c 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,43 @@ To install the package, run:
go get github.com/go-zoox/oauth2
```
+## Supported Providers
+
+This library supports many OAuth2 providers, including:
+
+- **Supabase** - Full-featured authentication platform
+- **GitHub** - Version control and collaboration
+- **Google** - Google services authentication
+- **Auth0** - Identity and access management
+- **Microsoft Azure** - Microsoft cloud services
+- **Slack** - Team communication platform
+- **Discord** - Gaming and community communication
+- **Facebook** - Social networking
+- **GitLab** - DevOps platform
+- **Twitter** - Social media platform
+- **WeChat** - Chinese messaging platform
+- **Doreamon** - Custom authentication provider
+- And many more...
+
+### Supabase Provider
+
+The Supabase provider offers seamless integration with Supabase Auth:
+
+```go
+import "github.com/go-zoox/oauth2/supabase"
+
+// Create Supabase client
+client, err := supabase.New(&supabase.SupabaseConfig{
+ BaseURL: "https://your-project.supabase.co",
+ ClientID: "your-client-id",
+ ClientSecret: "your-client-secret",
+ RedirectURI: "http://localhost:8080/auth/callback",
+ Scope: "openid email profile",
+})
+```
+
+For detailed Supabase setup instructions, see the [Supabase provider documentation](supabase/README.md).
+
## Getting Started
### Example 1: Using only one oauth2 provider => doreamon
diff --git a/example/supabase/.env.example b/example/supabase/.env.example
new file mode 100644
index 0000000..4d78066
--- /dev/null
+++ b/example/supabase/.env.example
@@ -0,0 +1,16 @@
+# Supabase OAuth2 Configuration
+# Copy this file to .env and fill in your actual values
+
+# Your Supabase project URL (found in your Supabase dashboard)
+SUPABASE_BASE_URL=https://your-project-id.supabase.co
+
+# OAuth2 credentials from your Supabase project
+# These can be found in: Authentication > Settings > OAuth2
+SUPABASE_CLIENT_ID=your-client-id
+SUPABASE_CLIENT_SECRET=your-client-secret
+
+# Callback URL - make sure this matches what you set in Supabase dashboard
+SUPABASE_REDIRECT_URI=http://localhost:8080/auth/callback
+
+# Optional: Port for the example server (defaults to 8080)
+PORT=8080
\ No newline at end of file
diff --git a/example/supabase/main.go b/example/supabase/main.go
new file mode 100644
index 0000000..6024af5
--- /dev/null
+++ b/example/supabase/main.go
@@ -0,0 +1,163 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+
+ "github.com/go-zoox/oauth2"
+ "github.com/go-zoox/oauth2/supabase"
+)
+
+func main() {
+ // Environment variables needed:
+ // SUPABASE_BASE_URL=https://your-project.supabase.co
+ // SUPABASE_CLIENT_ID=your-client-id
+ // SUPABASE_CLIENT_SECRET=your-client-secret
+ // SUPABASE_REDIRECT_URI=http://localhost:8080/auth/callback
+
+ baseURL := os.Getenv("SUPABASE_BASE_URL")
+ clientID := os.Getenv("SUPABASE_CLIENT_ID")
+ clientSecret := os.Getenv("SUPABASE_CLIENT_SECRET")
+ redirectURI := os.Getenv("SUPABASE_REDIRECT_URI")
+
+ if baseURL == "" || clientID == "" || clientSecret == "" || redirectURI == "" {
+ log.Fatal("Missing required environment variables: SUPABASE_BASE_URL, SUPABASE_CLIENT_ID, SUPABASE_CLIENT_SECRET, SUPABASE_REDIRECT_URI")
+ }
+
+ // Create Supabase OAuth2 client
+ client, err := supabase.New(&supabase.SupabaseConfig{
+ BaseURL: baseURL,
+ ClientID: clientID,
+ ClientSecret: clientSecret,
+ RedirectURI: redirectURI,
+ Scope: "openid email profile",
+ })
+ if err != nil {
+ log.Fatal("Failed to create Supabase client:", err)
+ }
+
+ // Home page
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ html := `
+
+
+
+ Supabase OAuth2 Example
+
+
+
+ Supabase OAuth2 Example
+ This is a simple example of using Supabase OAuth2 authentication.
+ Login with Supabase
+ Logout
+
+
+ `
+ w.Header().Set("Content-Type", "text/html")
+ w.Write([]byte(html))
+ })
+
+ // Login endpoint
+ http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
+ client.Authorize("oauth2-state", func(loginURL string) {
+ http.Redirect(w, r, loginURL, http.StatusFound)
+ })
+ })
+
+ // Logout endpoint
+ http.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
+ client.Logout(func(logoutURL string) {
+ if logoutURL == "" {
+ // If no logout URL provided, redirect to home
+ http.Redirect(w, r, "/", http.StatusFound)
+ } else {
+ http.Redirect(w, r, logoutURL, http.StatusFound)
+ }
+ })
+ })
+
+ // OAuth callback endpoint
+ http.HandleFunc("/auth/callback", func(w http.ResponseWriter, r *http.Request) {
+ code := r.URL.Query().Get("code")
+ state := r.URL.Query().Get("state")
+
+ client.Callback(code, state, func(user *oauth2.User, token *oauth2.Token, err error) {
+ if err != nil {
+ log.Printf("OAuth callback error: %v", err)
+ http.Error(w, "Authentication failed: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Successful authentication
+ log.Printf("User authenticated: %+v", user)
+ log.Printf("Token: %+v", token)
+
+ // Create a simple success page
+ html := `
+
+
+
+ Authentication Success
+
+
+
+ Authentication Success!
+
+
Welcome, you have successfully authenticated with Supabase!
+
+
+
User Information:
+
ID: %s
+
Email: %s
+
Username: %s
+
Nickname: %s
+
+ Go Home
+
+
+ `
+ response := fmt.Sprintf(html, user.ID, user.Email, user.Username, user.Nickname)
+ w.Header().Set("Content-Type", "text/html")
+ w.Write([]byte(response))
+ })
+ })
+
+ // Start the server
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "8080"
+ }
+
+ log.Printf("Starting server on port %s", port)
+ log.Printf("Visit http://localhost:%s to test the Supabase OAuth2 integration", port)
+ log.Fatal(http.ListenAndServe(":"+port, nil))
+}
\ No newline at end of file
diff --git a/example/supabase/supabase-example b/example/supabase/supabase-example
new file mode 100755
index 0000000..cac1218
Binary files /dev/null and b/example/supabase/supabase-example differ
diff --git a/go.mod b/go.mod
index 6ddb7fc..67d10a5 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,8 @@
module github.com/go-zoox/oauth2
-go 1.19
+go 1.23.0
+
+toolchain go1.24.2
require (
github.com/go-zoox/cookie v1.2.0
diff --git a/go.sum b/go.sum
index 900993e..40070b7 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,5 @@
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/go-zoox/chalk v1.0.2 h1:DCWft37fogmvqF37JdbGSLg28L/tQeA8u0lMvb62KOg=
github.com/go-zoox/chalk v1.0.2/go.mod h1:z5+qvE9nEJI5uT4px2tyoFa/xxkqf3CUo22KmXLKbNI=
github.com/go-zoox/cookie v1.2.0 h1:MO33lPQ/QGJIAEzgrsAfEpJc25lcJ/XR0w+smM19sNQ=
@@ -14,13 +15,18 @@ github.com/go-zoox/headers v1.0.8/go.mod h1:WEgEbewswEw4n4qS1iG68Kn/vOQVCAKGwwuZ
github.com/go-zoox/logger v1.4.6 h1:zHUaB6KQ9rD/N3hM0JJ3/JCNdgtedf4mVBBNNSyWCOg=
github.com/go-zoox/logger v1.4.6/go.mod h1:o7ddvv/gMoMa0TomPhHoIz11ZWRbQ92pF6rwYbOY3iQ=
github.com/go-zoox/testify v1.0.2 h1:G5sQ3xm0uwCuytnMhgnqZ5BItCt2DN3n2wLBqlIJEWA=
+github.com/go-zoox/testify v1.0.2/go.mod h1:L35iVL6xDKDL/TQOTRWyNL4H4nm8bzs6nde5XA7PYnY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
@@ -31,6 +37,7 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=
+github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/supabase/README.md b/supabase/README.md
new file mode 100644
index 0000000..0c3c025
--- /dev/null
+++ b/supabase/README.md
@@ -0,0 +1,193 @@
+# Supabase OAuth2 Provider
+
+This package provides Supabase authentication support for the [go-zoox/oauth2](https://github.com/go-zoox/oauth2) library.
+
+## Features
+
+- Full OAuth2 integration with Supabase Auth
+- Support for custom Supabase project URLs
+- Automatic user information extraction
+- Token refresh support
+- Customizable scopes
+
+## Prerequisites
+
+1. A Supabase project - Create one at [https://supabase.com](https://supabase.com)
+2. OAuth2 application configured in your Supabase project
+
+## Configuration
+
+### 1. Set up OAuth2 in Supabase Dashboard
+
+1. Go to your Supabase project dashboard
+2. Navigate to **Authentication** > **Settings**
+3. In the **Site URL** section, add your application's URL
+4. In the **Redirect URLs** section, add your callback URL (e.g., `http://localhost:8080/auth/callback`)
+5. Note down your project URL, it will be something like `https://your-project-id.supabase.co`
+
+### 2. Environment Variables
+
+Set the following environment variables:
+
+```bash
+export SUPABASE_BASE_URL="https://your-project-id.supabase.co"
+export SUPABASE_CLIENT_ID="your-client-id"
+export SUPABASE_CLIENT_SECRET="your-client-secret"
+export SUPABASE_REDIRECT_URI="http://localhost:8080/auth/callback"
+```
+
+## Usage
+
+### Basic Usage
+
+```go
+package main
+
+import (
+ "log"
+ "github.com/go-zoox/oauth2"
+ "github.com/go-zoox/oauth2/supabase"
+)
+
+func main() {
+ // Create Supabase OAuth2 client
+ client, err := supabase.New(&supabase.SupabaseConfig{
+ BaseURL: "https://your-project-id.supabase.co",
+ ClientID: "your-client-id",
+ ClientSecret: "your-client-secret",
+ RedirectURI: "http://localhost:8080/auth/callback",
+ Scope: "openid email profile",
+ })
+ if err != nil {
+ log.Fatal("Failed to create Supabase client:", err)
+ }
+
+ // Start authentication flow
+ client.Authorize("state-value", func(loginURL string) {
+ // Redirect user to loginURL
+ log.Println("Visit:", loginURL)
+ })
+}
+```
+
+### Handle OAuth Callback
+
+```go
+// Handle the OAuth callback
+client.Callback(code, state, func(user *oauth2.User, token *oauth2.Token, err error) {
+ if err != nil {
+ log.Printf("Authentication failed: %v", err)
+ return
+ }
+
+ // Authentication successful
+ log.Printf("User: %+v", user)
+ log.Printf("Token: %+v", token)
+
+ // User information available:
+ // user.ID - User's unique ID
+ // user.Email - User's email address
+ // user.Username - User's username
+ // user.Nickname - User's display name
+ // user.Avatar - User's avatar URL
+})
+```
+
+### Custom Scopes
+
+```go
+client, err := supabase.New(&supabase.SupabaseConfig{
+ BaseURL: "https://your-project-id.supabase.co",
+ ClientID: "your-client-id",
+ ClientSecret: "your-client-secret",
+ RedirectURI: "http://localhost:8080/auth/callback",
+ Scope: "openid email profile user_metadata", // Custom scopes
+})
+```
+
+## Configuration Options
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `BaseURL` | string | Yes | Your Supabase project URL (e.g., `https://your-project.supabase.co`) |
+| `ClientID` | string | Yes | OAuth2 client ID from your Supabase project |
+| `ClientSecret` | string | Yes | OAuth2 client secret from your Supabase project |
+| `RedirectURI` | string | Yes | Callback URL after authentication |
+| `Scope` | string | No | OAuth2 scopes (default: `"openid email profile"`) |
+
+## User Information
+
+The following user information is automatically extracted from Supabase:
+
+- **ID**: User's unique identifier
+- **Email**: User's email address
+- **Username**: User's username (falls back to email if not set)
+- **Nickname**: User's display name from `user_metadata.full_name`
+- **Avatar**: User's avatar URL from `user_metadata.avatar_url`
+
+## Example Application
+
+See the [example](../example/supabase/) directory for a complete working example with a web server.
+
+To run the example:
+
+1. Set the required environment variables
+2. Run the example:
+ ```bash
+ cd example/supabase
+ go run main.go
+ ```
+3. Visit `http://localhost:8080` in your browser
+
+## Error Handling
+
+The provider handles common OAuth2 errors:
+
+- Invalid credentials
+- Missing configuration
+- Network errors
+- Invalid callback parameters
+
+Always check for errors in the callback function:
+
+```go
+client.Callback(code, state, func(user *oauth2.User, token *oauth2.Token, err error) {
+ if err != nil {
+ // Handle authentication error
+ log.Printf("Authentication failed: %v", err)
+ return
+ }
+ // Success case
+})
+```
+
+## Security Considerations
+
+1. **Environment Variables**: Store sensitive information like client secrets in environment variables
+2. **HTTPS**: Always use HTTPS in production
+3. **State Parameter**: Use a random state parameter to prevent CSRF attacks
+4. **Scope Limitation**: Only request the minimum scopes required for your application
+5. **Token Storage**: Store tokens securely and consider encryption for sensitive data
+
+## Troubleshooting
+
+### Common Issues
+
+1. **"Invalid redirect URI"**: Ensure your redirect URI is exactly the same in your code and Supabase dashboard
+2. **"Invalid client"**: Check that your client ID and secret are correct
+3. **"Base URL required"**: Make sure you provide the full Supabase project URL
+4. **CORS errors**: Configure CORS settings in your Supabase dashboard if needed
+
+### Debug Mode
+
+Enable debug logging to see OAuth2 flow details:
+
+```go
+import "github.com/go-zoox/logger"
+
+logger.SetLevel(logger.DEBUG)
+```
+
+## License
+
+This package is part of the [go-zoox/oauth2](https://github.com/go-zoox/oauth2) library and follows the same license terms.
\ No newline at end of file
diff --git a/supabase/supabase.go b/supabase/supabase.go
new file mode 100644
index 0000000..a75e30d
--- /dev/null
+++ b/supabase/supabase.go
@@ -0,0 +1,84 @@
+package supabase
+
+import (
+ "fmt"
+ "net/url"
+
+ "github.com/go-zoox/oauth2"
+)
+
+type SupabaseConfig struct {
+ // Basic OAuth2 configuration
+ ClientID string `json:"client_id"`
+ ClientSecret string `json:"client_secret"`
+ RedirectURI string `json:"redirect_uri"`
+ Scope string `json:"scope"`
+ // Supabase specific configuration
+ BaseURL string `json:"base_url"` // e.g., "https://your-project.supabase.co"
+}
+
+func New(cfg *SupabaseConfig) (oauth2.Client, error) {
+ if cfg.BaseURL == "" {
+ return nil, fmt.Errorf("supabase: base_url is required")
+ }
+
+ scope := cfg.Scope
+ if scope == "" {
+ scope = "openid email profile"
+ }
+
+ // Ensure BaseURL doesn't have trailing slash
+ baseURL := cfg.BaseURL
+ if baseURL[len(baseURL)-1] == '/' {
+ baseURL = baseURL[:len(baseURL)-1]
+ }
+
+ config := oauth2.Config{
+ Name: "Supabase",
+ AuthURL: baseURL + "/auth/v1/authorize",
+ TokenURL: baseURL + "/auth/v1/token",
+ UserInfoURL: baseURL + "/auth/v1/user",
+ LogoutURL: baseURL + "/auth/v1/logout",
+ Scope: scope,
+ RedirectURI: cfg.RedirectURI,
+ ClientID: cfg.ClientID,
+ ClientSecret: cfg.ClientSecret,
+ //
+ AccessTokenAttributeName: "access_token",
+ RefreshTokenAttributeName: "refresh_token",
+ ExpiresInAttributeName: "expires_in",
+ TokenTypeAttributeName: "token_type",
+ //
+ EmailAttributeName: "email",
+ IDAttributeName: "id",
+ NicknameAttributeName: "user_metadata.full_name",
+ AvatarAttributeName: "user_metadata.avatar_url",
+ HomepageAttributeName: "user_metadata.website",
+ //
+ BaseURL: baseURL,
+ }
+
+ // Custom register URL for Supabase
+ config.GetRegisterURL = func(oac *oauth2.Config) string {
+ // Supabase doesn't have a standard register endpoint, redirect to auth
+ return fmt.Sprintf("%s/auth/v1/signup", baseURL)
+ }
+
+ // Custom login URL to handle Supabase's OAuth flow
+ config.GetLoginURL = func(oac *oauth2.Config, state string) string {
+ clientID := oac.ClientID
+ redirectURI := oac.RedirectURI
+ scope := oac.Scope
+
+ params := url.Values{}
+ params.Add("client_id", clientID)
+ params.Add("redirect_uri", redirectURI)
+ params.Add("response_type", "code")
+ params.Add("scope", scope)
+ params.Add("state", state)
+
+ return fmt.Sprintf("%s?%s", oac.AuthURL, params.Encode())
+ }
+
+ return oauth2.New(config)
+}
\ No newline at end of file