Skip to content

Commit dbd5cd5

Browse files
committed
feat: Enhance OAuth2 support with multi-application configuration and CORS middleware
- Introduced support for multiple applications using the same OAuth endpoints with different redirect URIs. - Added environment variable configurations for allowed redirect domains and default redirect URIs. - Implemented CORS middleware to manage cross-origin requests based on the environment. - Updated OAuth2 handlers to securely manage redirect URIs and state parameters, improving security against open redirect vulnerabilities. - Enhanced API documentation to reflect new multi-application OAuth configuration and usage examples.
1 parent 334935b commit dbd5cd5

File tree

7 files changed

+649
-44
lines changed

7 files changed

+649
-44
lines changed

cmd/api/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ func main() {
8282
// Setup Gin Router
8383
r := gin.Default()
8484

85+
// Add CORS middleware
86+
r.Use(middleware.CORSMiddleware())
87+
8588
// Public routes
8689
public := r.Group("/")
8790
{

docs/multi-app-oauth-config.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Multi-Application OAuth Configuration
2+
3+
## Overview
4+
The authentication API now supports multiple applications using the same OAuth endpoints with different redirect URIs. This allows you to have multiple frontends (e.g., admin panel, user portal, mobile app) that all use the same authentication backend.
5+
6+
## Configuration
7+
8+
### Environment Variables
9+
10+
Add these variables to your `.env` file:
11+
12+
```env
13+
# Multi-Application Support
14+
# Comma-separated list of allowed redirect domains for OAuth callbacks
15+
ALLOWED_REDIRECT_DOMAINS=localhost:3000,localhost:5173,localhost:8080,example.com,.example.com
16+
17+
# Default redirect URI when none is specified
18+
DEFAULT_REDIRECT_URI=http://localhost:5173/auth/callback
19+
20+
# Production frontend URL for CORS
21+
FRONTEND_URL=https://your-production-domain.com
22+
```
23+
24+
### Domain Configuration
25+
26+
#### Development
27+
For local development, include all your local ports:
28+
```env
29+
ALLOWED_REDIRECT_DOMAINS=localhost:3000,localhost:5173,localhost:8080,127.0.0.1:3000,127.0.0.1:5173
30+
```
31+
32+
#### Production
33+
For production, specify your allowed domains:
34+
```env
35+
# Allow specific domains
36+
ALLOWED_REDIRECT_DOMAINS=myapp.com,admin.myapp.com
37+
38+
# Allow all subdomains with dot notation
39+
ALLOWED_REDIRECT_DOMAINS=.myapp.com,anotherapp.com
40+
```
41+
42+
## Usage
43+
44+
### Frontend Integration
45+
46+
#### 1. Basic Usage (Default Redirect)
47+
```javascript
48+
// Will redirect to DEFAULT_REDIRECT_URI after OAuth
49+
window.location.href = '/auth/google/login';
50+
```
51+
52+
#### 2. Custom Redirect URI
53+
```javascript
54+
// Will redirect to specified URI after OAuth
55+
const redirectUri = 'https://admin.myapp.com/auth/callback';
56+
window.location.href = `/auth/google/login?redirect_uri=${encodeURIComponent(redirectUri)}`;
57+
```
58+
59+
#### 3. Handling Callbacks
60+
Your frontend should handle the callback URL parameters:
61+
62+
```javascript
63+
// In your /auth/callback route
64+
const urlParams = new URLSearchParams(window.location.search);
65+
66+
if (urlParams.get('error')) {
67+
// Handle error
68+
console.error('OAuth error:', urlParams.get('error'));
69+
} else if (urlParams.get('access_token')) {
70+
// Handle success
71+
const accessToken = urlParams.get('access_token');
72+
const refreshToken = urlParams.get('refresh_token');
73+
const provider = urlParams.get('provider'); // 'google', 'facebook', or 'github'
74+
75+
// Store tokens and redirect to app
76+
localStorage.setItem('access_token', accessToken);
77+
localStorage.setItem('refresh_token', refreshToken);
78+
window.location.href = '/dashboard';
79+
}
80+
```
81+
82+
### API Endpoints
83+
84+
All OAuth providers support the same pattern:
85+
86+
- **Google**:
87+
- Login: `GET /auth/google/login?redirect_uri=...`
88+
- Callback: `GET /auth/google/callback`
89+
90+
- **Facebook**:
91+
- Login: `GET /auth/facebook/login?redirect_uri=...`
92+
- Callback: `GET /auth/facebook/callback`
93+
94+
- **GitHub**:
95+
- Login: `GET /auth/github/login?redirect_uri=...`
96+
- Callback: `GET /auth/github/callback`
97+
98+
## Security Features
99+
100+
### 1. Domain Whitelist
101+
- Only domains in `ALLOWED_REDIRECT_DOMAINS` are accepted
102+
- Prevents open redirect vulnerabilities
103+
- Supports subdomain wildcards with dot notation
104+
105+
### 2. Secure State Management
106+
- OAuth state parameter contains encrypted redirect URI
107+
- Includes timestamp to prevent replay attacks
108+
- Cryptographically secure random nonce generation
109+
110+
### 3. CORS Configuration
111+
- Automatic CORS headers for allowed domains
112+
- Supports credentials for secure cookie handling
113+
- Production-ready with configurable origins
114+
115+
## Examples
116+
117+
### Multi-Domain Setup
118+
```env
119+
# Support multiple applications
120+
ALLOWED_REDIRECT_DOMAINS=app.mycompany.com,admin.mycompany.com,mobile.mycompany.com
121+
DEFAULT_REDIRECT_URI=https://app.mycompany.com/auth/callback
122+
```
123+
124+
### Development Setup
125+
```env
126+
# Support local development
127+
ALLOWED_REDIRECT_DOMAINS=localhost:3000,localhost:5173,localhost:8080
128+
DEFAULT_REDIRECT_URI=http://localhost:5173/auth/callback
129+
```
130+
131+
### Production with Subdomains
132+
```env
133+
# Allow all subdomains of mycompany.com
134+
ALLOWED_REDIRECT_DOMAINS=.mycompany.com,mycompany.com
135+
DEFAULT_REDIRECT_URI=https://mycompany.com/auth/callback
136+
```
137+
138+
## Error Handling
139+
140+
The API will redirect to the frontend with error parameters:
141+
142+
- `?error=invalid_state` - Invalid or expired OAuth state
143+
- `?error=authorization_code_missing` - OAuth provider didn't return code
144+
- `?error=missing_state` - OAuth state parameter missing
145+
- `?error=Invalid%20redirect%20URI` - Redirect URI not in whitelist
146+
147+
## Migration Guide
148+
149+
### From Single Application
150+
If you were using the hardcoded redirect URI:
151+
152+
1. Add the environment variables to your `.env` file
153+
2. Your existing setup will continue to work with default values
154+
3. Optionally, start using the `redirect_uri` parameter for flexibility
155+
156+
### For New Applications
157+
1. Set up the environment variables
158+
2. Add your domain to `ALLOWED_REDIRECT_DOMAINS`
159+
3. Use the `redirect_uri` parameter in your OAuth login URLs

go.mod

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ require (
2727
filippo.io/edwards25519 v1.1.0 // indirect
2828
github.com/KyleBanks/depth v1.2.1 // indirect
2929
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
30-
github.com/bytedance/sonic v1.11.6 // indirect
31-
github.com/bytedance/sonic/loader v0.1.1 // indirect
30+
github.com/bytedance/sonic v1.13.3 // indirect
31+
github.com/bytedance/sonic/loader v0.2.4 // indirect
3232
github.com/cespare/xxhash/v2 v2.3.0 // indirect
33-
github.com/cloudwego/base64x v0.1.4 // indirect
33+
github.com/cloudwego/base64x v0.1.5 // indirect
3434
github.com/cloudwego/iasm v0.2.0 // indirect
3535
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
3636
github.com/fsnotify/fsnotify v1.8.0 // indirect
37-
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
38-
github.com/gin-contrib/sse v0.1.0 // indirect
37+
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
38+
github.com/gin-contrib/cors v1.7.6 // indirect
39+
github.com/gin-contrib/sse v1.1.0 // indirect
3940
github.com/go-openapi/jsonpointer v0.21.1 // indirect
4041
github.com/go-openapi/jsonreference v0.21.0 // indirect
4142
github.com/go-openapi/spec v0.21.0 // indirect
@@ -44,7 +45,7 @@ require (
4445
github.com/go-playground/universal-translator v0.18.1 // indirect
4546
github.com/go-sql-driver/mysql v1.8.1 // indirect
4647
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
47-
github.com/goccy/go-json v0.10.2 // indirect
48+
github.com/goccy/go-json v0.10.5 // indirect
4849
github.com/jackc/pgpassfile v1.0.0 // indirect
4950
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
5051
github.com/jackc/pgx/v5 v5.6.0 // indirect
@@ -53,13 +54,13 @@ require (
5354
github.com/jinzhu/now v1.1.5 // indirect
5455
github.com/josharian/intern v1.0.0 // indirect
5556
github.com/json-iterator/go v1.1.12 // indirect
56-
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
57+
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
5758
github.com/leodido/go-urn v1.4.0 // indirect
5859
github.com/mailru/easyjson v0.9.0 // indirect
5960
github.com/mattn/go-isatty v0.0.20 // indirect
6061
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
6162
github.com/modern-go/reflect2 v1.0.2 // indirect
62-
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
63+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
6364
github.com/pquerna/otp v1.5.0 // indirect
6465
github.com/sagikazarmark/locafero v0.7.0 // indirect
6566
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
@@ -69,16 +70,16 @@ require (
6970
github.com/spf13/pflag v1.0.6 // indirect
7071
github.com/subosito/gotenv v1.6.0 // indirect
7172
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
72-
github.com/ugorji/go/codec v1.2.12 // indirect
73+
github.com/ugorji/go/codec v1.3.0 // indirect
7374
go.uber.org/atomic v1.9.0 // indirect
7475
go.uber.org/multierr v1.9.0 // indirect
75-
golang.org/x/arch v0.8.0 // indirect
76+
golang.org/x/arch v0.18.0 // indirect
7677
golang.org/x/net v0.41.0 // indirect
7778
golang.org/x/sync v0.15.0 // indirect
7879
golang.org/x/sys v0.33.0 // indirect
7980
golang.org/x/text v0.26.0 // indirect
8081
golang.org/x/tools v0.34.0 // indirect
81-
google.golang.org/protobuf v1.36.1 // indirect
82+
google.golang.org/protobuf v1.36.6 // indirect
8283
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
8384
gopkg.in/yaml.v3 v3.0.1 // indirect
8485
gorm.io/datatypes v1.2.5 // indirect

go.sum

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
88
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
99
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
1010
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
11+
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
12+
github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
1113
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
1214
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
15+
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
16+
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
1317
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
1418
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1519
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
1620
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
21+
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
22+
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
1723
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
1824
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
1925
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -27,10 +33,16 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
2733
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
2834
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
2935
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
36+
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
37+
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
38+
github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=
39+
github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=
3040
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
3141
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
3242
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
3343
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
44+
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
45+
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
3446
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
3547
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
3648
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
@@ -58,6 +70,8 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
5870
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
5971
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
6072
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
73+
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
74+
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
6175
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
6276
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
6377
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -86,6 +100,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
86100
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
87101
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
88102
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
103+
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
104+
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
89105
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
90106
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
91107
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -110,6 +126,8 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
110126
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
111127
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
112128
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
129+
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
130+
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
113131
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
114132
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
115133
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
@@ -152,6 +170,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
152170
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
153171
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
154172
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
173+
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
174+
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
155175
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
156176
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
157177
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -160,6 +180,8 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV
160180
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
161181
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
162182
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
183+
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
184+
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
163185
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
164186
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
165187
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
@@ -205,6 +227,8 @@ golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg
205227
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
206228
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
207229
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
230+
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
231+
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
208232
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
209233
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
210234
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/middleware/cors.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package middleware
2+
3+
import (
4+
"time"
5+
6+
"github.com/gin-contrib/cors"
7+
"github.com/gin-gonic/gin"
8+
"github.com/spf13/viper"
9+
)
10+
11+
// CORSMiddleware creates and configures CORS middleware
12+
func CORSMiddleware() gin.HandlerFunc {
13+
config := cors.Config{
14+
AllowOrigins: []string{
15+
"http://localhost:3000", // React dev server
16+
"http://localhost:5173", // Vite dev server
17+
"http://localhost:8080", // API server itself
18+
"https://accounts.google.com", // Google OAuth
19+
"https://www.facebook.com", // Facebook OAuth
20+
"https://github.com", // GitHub OAuth
21+
},
22+
AllowMethods: []string{
23+
"GET",
24+
"POST",
25+
"PUT",
26+
"DELETE",
27+
"OPTIONS",
28+
"HEAD",
29+
},
30+
AllowHeaders: []string{
31+
"Origin",
32+
"Content-Type",
33+
"Content-Length",
34+
"Accept-Encoding",
35+
"X-CSRF-Token",
36+
"Authorization",
37+
"Accept",
38+
"Cache-Control",
39+
"X-Requested-With",
40+
},
41+
ExposeHeaders: []string{
42+
"Content-Length",
43+
"Access-Control-Allow-Origin",
44+
"Access-Control-Allow-Headers",
45+
"Content-Type",
46+
},
47+
AllowCredentials: true,
48+
MaxAge: 12 * time.Hour,
49+
}
50+
51+
// In production, restrict origins to specific domains
52+
if viper.GetString("GIN_MODE") == "release" {
53+
// Get frontend URLs from environment
54+
frontendURL := viper.GetString("FRONTEND_URL")
55+
if frontendURL != "" {
56+
config.AllowOrigins = []string{
57+
frontendURL,
58+
"https://accounts.google.com",
59+
"https://www.facebook.com",
60+
"https://github.com",
61+
}
62+
}
63+
}
64+
65+
return cors.New(config)
66+
}

0 commit comments

Comments
 (0)