aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorVidhu Kant Sharma <vidhukant@vidhukant.com>2025-10-10 17:29:30 +0530
committerVidhu Kant Sharma <vidhukant@vidhukant.com>2025-10-10 17:29:30 +0530
commitb0f5cefba592f6bc7166cdd5d83899dc2bbcb355 (patch)
treea14584ac41b4d9915813db7c63c95248cf8c3dab
parent19c79de205674b0932b13162e779b311ac93444b (diff)
added refresh token versioningv0.12.0
-rw-r--r--auth/auth.go6
-rw-r--r--auth/controller.go29
-rw-r--r--main.go2
-rw-r--r--user/user.go3
4 files changed, 33 insertions, 7 deletions
diff --git a/auth/auth.go b/auth/auth.go
index 7116a2c..4ac6445 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -26,6 +26,12 @@ type AuthClaims struct {
UserID uint `json:"userid"`
}
+type RefreshClaims struct {
+ jwt.RegisteredClaims
+ UserID uint `json:"userid"`
+ Version uint `json:"version"`
+}
+
type LoginReq struct {
AccountName string
Method string
diff --git a/auth/controller.go b/auth/controller.go
index 7e3346e..05cdd9d 100644
--- a/auth/controller.go
+++ b/auth/controller.go
@@ -103,12 +103,13 @@ func handleSignIn (ctx *gin.Context) {
}
refreshToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256,
- AuthClaims {
+ RefreshClaims {
jwt.RegisteredClaims {
IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 6)),
},
u.ID,
+ u.TokenVersion,
},
).SignedString(REFRESH_KEY)
if err != nil {
@@ -137,13 +138,34 @@ func handleRefresh (ctx *gin.Context) {
return []byte(REFRESH_KEY), nil
})
- claims, ok := tk.Claims.(*AuthClaims)
+ claims, ok := tk.Claims.(*RefreshClaims)
if !ok {
ctx.Error(errors.ErrUnauthorized)
ctx.Abort()
return
}
+ // check token version
+ var u user.User
+ err := user.GetUser(&u, claims.UserID)
+ if err != nil {
+ if err == errors.ErrNotFound {
+ ctx.Error(errors.ErrUnauthorized)
+ ctx.Abort()
+ return
+ } else {
+ ctx.Error(err)
+ ctx.Abort()
+ return
+ }
+ }
+ if (u.TokenVersion != claims.Version) {
+ ctx.Error(errors.ErrSessionExpired)
+ ctx.Abort()
+ return
+ }
+
+
if !tk.Valid {
eat := claims.ExpiresAt.Unix()
if eat != 0 && eat < time.Now().Unix() {
@@ -156,8 +178,6 @@ func handleRefresh (ctx *gin.Context) {
return
}
- // TODO: if token is valid, check if user even exists before generating authToken
-
authToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256,
AuthClaims {
jwt.RegisteredClaims {
@@ -177,6 +197,5 @@ func handleRefresh (ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"auth_token": authToken,
"message": "success",
- //"data": u,
})
}
diff --git a/main.go b/main.go
index 6d2ef53..90d5d3a 100644
--- a/main.go
+++ b/main.go
@@ -38,7 +38,7 @@ import (
"log"
)
-const OPENBILLS_VERSION = "v0.11.1"
+const OPENBILLS_VERSION = "v0.12.0"
func init() {
if !viper.GetBool("debug_mode") {
diff --git a/user/user.go b/user/user.go
index b130ab9..dbcbad0 100644
--- a/user/user.go
+++ b/user/user.go
@@ -40,6 +40,7 @@ func init() {
type User struct {
gorm.Model
u.Address
+ TokenVersion uint // this can be incremented to disable existing refresh token(s)
FullName string
FirmName string
Gstin string
@@ -50,9 +51,9 @@ type User struct {
Password string
LogoFile string
SignatureFile string
+ IsVerified bool // this should be removed and tokens should be issued upon verification
// will be printed with address on the invoice
Details string
- IsVerified bool
// a note is printed on every invoice.
// This is the default that gets automatically set
DefaultInvoiceNote string