Skip to content

Commit dfce258

Browse files
committed
feat: oauth login allows 10s verification window
1 parent 4fd5e49 commit dfce258

3 files changed

Lines changed: 29 additions & 10 deletions

File tree

internal/api/auth/oauth.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,19 @@ func (h *OAuthHandler) OAuthStatus(c *gin.Context) {
5757
c.JSON(http.StatusAccepted, gin.H{"error": "not_found"})
5858
return
5959
}
60-
if cb.Used {
60+
61+
// Already used and outside the 10-second reuse window
62+
if cb.Used && !h.OAuthService.IsWithinReuseWindow(cb) {
6163
c.JSON(http.StatusGone, gin.H{"error": "used"})
6264
return
6365
}
6466

65-
// update used to true
66-
err = h.OAuthService.OAuthMakeUsed(ctx, cb)
67-
if err != nil {
68-
c.JSON(http.StatusInternalServerError, gin.H{"error": "update_used_failed"})
69-
return
67+
// Mark as used (first use)
68+
if !cb.Used {
69+
if err := h.OAuthService.OAuthMakeUsed(ctx, cb); err != nil {
70+
c.JSON(http.StatusInternalServerError, gin.H{"error": "update_used_failed"})
71+
return
72+
}
7073
}
7174

7275
c.JSON(http.StatusOK, gin.H{"code": cb.Code, "access_token": cb.AccessToken})

internal/models/oauth.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package models
22

3+
import "go.mongodb.org/mongo-driver/v2/bson"
4+
35
type OAuth struct {
46
BaseModel `bson:",inline"`
5-
Code string `bson:"code,omitempty"` // OAuth code (authorization code) in Google's implementation is single-use, short-lived, and temporarily unique.
6-
AccessToken string `bson:"access_token,omitempty"`
7-
State string `bson:"state,omitempty"`
8-
Used bool `bson:"used,omitempty"`
7+
Code string `bson:"code,omitempty"` // OAuth code (authorization code) in Google's implementation is single-use, short-lived, and temporarily unique.
8+
AccessToken string `bson:"access_token,omitempty"`
9+
State string `bson:"state,omitempty"`
10+
Used bool `bson:"used,omitempty"`
11+
UsedAt bson.DateTime `bson:"used_at,omitempty"` // Timestamp when the record was first marked as used, allows 10s reuse window
912
}
1013

1114
func (o OAuth) CollectionName() string {

internal/services/oauth.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,22 @@ func (s *OAuthService) OAuthMakeUsed(ctx context.Context, cb *models.OAuth) erro
102102
update := bson.M{
103103
"$set": bson.M{
104104
"used": true,
105+
"used_at": bson.NewDateTimeFromTime(now),
105106
"updated_at": bson.NewDateTimeFromTime(now),
106107
},
107108
}
108109
_, err := s.oauthCollection.UpdateOne(ctx, bson.M{"_id": cb.ID}, update)
109110
return err
110111
}
112+
113+
// OAuthReuseWindow is the time window (10 seconds) during which a used OAuth record can still be reused
114+
const OAuthReuseWindow = 10 * time.Second
115+
116+
// IsWithinReuseWindow checks if the OAuth record was used within the reuse window
117+
func (s *OAuthService) IsWithinReuseWindow(cb *models.OAuth) bool {
118+
if !cb.Used || cb.UsedAt == 0 {
119+
return false
120+
}
121+
usedAt := cb.UsedAt.Time()
122+
return time.Since(usedAt) <= OAuthReuseWindow
123+
}

0 commit comments

Comments
 (0)