Skip to content

Commit 2f3aeaf

Browse files
committed
feat: Implement OAuth2 authentication with Google and GitHub support, including configuration and UI updates
1 parent d43dee5 commit 2f3aeaf

14 files changed

Lines changed: 607 additions & 7 deletions

File tree

.env.example

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,28 @@ OAUTH2_REDIS_DB=0
232232
# Path to translation files for multi-language support
233233
APISERVER_I18N_PATH=/etc/unla/i18n
234234

235+
# =============================================================================
236+
# EXTERNAL OAUTH PROVIDERS
237+
# =============================================================================
238+
239+
# Google OAuth Configuration
240+
# Get these from Google Cloud Console: https://console.cloud.google.com/
241+
# 1. Create a new project or select existing one
242+
# 2. Enable Google+ API
243+
# 3. Create OAuth 2.0 credentials
244+
# 4. Add authorized redirect URIs: http://localhost:5234/api/auth/oauth/google/callback
245+
GOOGLE_OAUTH_CLIENT_ID=
246+
GOOGLE_OAUTH_CLIENT_SECRET=
247+
GOOGLE_OAUTH_REDIRECT_URI=http://localhost:5234/api/auth/oauth/google/callback
248+
249+
# GitHub OAuth Configuration
250+
# Get these from GitHub Settings: https://github.com/settings/developers
251+
# 1. Register a new OAuth App
252+
# 2. Set Authorization callback URL: http://localhost:5234/api/auth/oauth/github/callback
253+
GITHUB_OAUTH_CLIENT_ID=
254+
GITHUB_OAUTH_CLIENT_SECRET=
255+
GITHUB_OAUTH_REDIRECT_URI=http://localhost:5234/api/auth/oauth/github/callback
256+
235257
# =============================================================================
236258
# STRIPE PAYMENT CONFIGURATION (PRO VERSION)
237259
# =============================================================================

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,5 @@ data
7373
dist
7474
bin
7575

76-
.history/*
76+
.history/*
77+
apiserver

cmd/apiserver/main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/amoylab/unla/internal/apiserver/database"
1111
apiserverHandler "github.com/amoylab/unla/internal/apiserver/handler"
1212
"github.com/amoylab/unla/internal/apiserver/middleware"
13+
"github.com/amoylab/unla/internal/auth"
1314
"github.com/amoylab/unla/internal/auth/jwt"
1415
"github.com/amoylab/unla/internal/common/cnst"
1516
"github.com/amoylab/unla/internal/common/config"
@@ -149,10 +150,25 @@ func initRouter(db database.Database, store storage.Store, ntf notifier.Notifier
149150
SecretKey: cfg.JWT.SecretKey,
150151
Duration: cfg.JWT.Duration,
151152
})
153+
154+
// Initialize OAuth auth service (for external providers)
155+
authService, err := auth.NewAuth(logger, cfg.Auth)
156+
if err != nil {
157+
logger.Fatal("Failed to initialize auth service", zap.Error(err))
158+
}
159+
152160
authH := apiserverHandler.NewHandler(db, jwtService, mcpCfg, logger)
161+
oauthH := apiserverHandler.NewOAuthHandler(db, jwtService, authService, logger)
153162

154163
authG := r.Group("/api/auth")
155164
authG.POST("/login", authH.Login)
165+
166+
// OAuth routes
167+
authG.GET("/oauth/providers", oauthH.GetOAuthProviders)
168+
authG.GET("/oauth/google/login", oauthH.GoogleLogin)
169+
authG.GET("/oauth/google/callback", oauthH.GoogleCallback)
170+
authG.GET("/oauth/github/login", oauthH.GitHubLogin)
171+
authG.GET("/oauth/github/callback", oauthH.GitHubCallback)
156172

157173
// Protected routes
158174
protected := r.Group("/api")

configs/apiserver.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,17 @@ stripe:
9191
success_url: "${STRIPE_SUCCESS_URL:https://amoylab.com}"
9292
cancel_url: "${STRIPE_CANCEL_URL:https://amoylab.com}"
9393
webhook_secret: "${STRIPE_WEBHOOK_SECRET:whsec_}"
94+
95+
# Authentication configuration
96+
auth:
97+
# Google OAuth configuration (optional)
98+
google:
99+
client_id: "${GOOGLE_OAUTH_CLIENT_ID:}"
100+
client_secret: "${GOOGLE_OAUTH_CLIENT_SECRET:}"
101+
redirect_uri: "${GOOGLE_OAUTH_REDIRECT_URI:http://localhost:5234/api/auth/oauth/google/callback}"
102+
103+
# GitHub OAuth configuration (optional)
104+
github:
105+
client_id: "${GITHUB_OAUTH_CLIENT_ID:}"
106+
client_secret: "${GITHUB_OAUTH_CLIENT_SECRET:}"
107+
redirect_uri: "${GITHUB_OAUTH_REDIRECT_URI:http://localhost:5234/api/auth/oauth/github/callback}"

internal/auth/auth.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ type Auth interface {
1515
OAuth2
1616
IsOAuth2Enabled() bool
1717
GetOAuth2CORS() *config.CORSConfig
18+
GetGoogleOAuth() ExternalOAuth
19+
GetGitHubOAuth() ExternalOAuth
20+
IsGoogleOAuthEnabled() bool
21+
IsGitHubOAuthEnabled() bool
1822
}
1923

2024
type OAuth2 interface {
@@ -66,6 +70,8 @@ type ClientRegistrationResponse struct {
6670
type auth struct {
6771
OAuth2
6872
cfg config.AuthConfig
73+
googleOAuth *GoogleOAuth
74+
githubOAuth *GitHubOAuth
6975
}
7076

7177
// NewAuth creates a new auth oauth based on the configuration
@@ -80,6 +86,12 @@ func NewAuth(logger *zap.Logger, cfg config.AuthConfig) (Auth, error) {
8086
}
8187
a.OAuth2 = oauth2
8288
}
89+
if cfg.Google != nil {
90+
a.googleOAuth = NewGoogleOAuth(logger, *cfg.Google)
91+
}
92+
if cfg.GitHub != nil {
93+
a.githubOAuth = NewGitHubOAuth(logger, *cfg.GitHub)
94+
}
8395
return a, nil
8496
}
8597

@@ -101,3 +113,23 @@ func (a *auth) ValidateToken(ctx context.Context, token string) error {
101113

102114
return a.OAuth2.ValidateToken(ctx, token)
103115
}
116+
117+
// GetGoogleOAuth returns the Google OAuth provider
118+
func (a *auth) GetGoogleOAuth() ExternalOAuth {
119+
return a.googleOAuth
120+
}
121+
122+
// GetGitHubOAuth returns the GitHub OAuth provider
123+
func (a *auth) GetGitHubOAuth() ExternalOAuth {
124+
return a.githubOAuth
125+
}
126+
127+
// IsGoogleOAuthEnabled returns true if Google OAuth is enabled
128+
func (a *auth) IsGoogleOAuthEnabled() bool {
129+
return a.cfg.Google != nil && a.googleOAuth != nil
130+
}
131+
132+
// IsGitHubOAuthEnabled returns true if GitHub OAuth is enabled
133+
func (a *auth) IsGitHubOAuthEnabled() bool {
134+
return a.cfg.GitHub != nil && a.githubOAuth != nil
135+
}

0 commit comments

Comments
 (0)