Brijesh's Git Server — identity @ main

authentication service

core/internal/auth/refresh_token.go (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
package auth

import (
	"fmt"
	"log"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var refreshSecretKey = []byte("my_refresh_secret_key")

type RefreshTokenClaims struct {
	ApplicationID string `json:"app_id"`
	jwt.RegisteredClaims
}

var accessSecretKey = []byte("my_access_secret_key")

type AccessTokenClaims struct {
	ApplicationID string `json:"app_id"`
	jwt.RegisteredClaims
}

func GenerateRefreshToken(applicationID string) (string, error) {
	claims := RefreshTokenClaims{
		ApplicationID: applicationID,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour * 7)), // Valid for 7 days
		},
	}

	// Create a new token object
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// Sign the token with the refresh secret key
	refreshToken, err := token.SignedString(refreshSecretKey)
	if err != nil {
		return "", err
	}

	return refreshToken, nil
}

func GenerateAccessTokenFromRefreshToken(refreshToken string) (string, error) {
	// Parse and validate the refresh token
	token, err := jwt.ParseWithClaims(refreshToken, &RefreshTokenClaims{}, func(token *jwt.Token) (interface{}, error) {
		return refreshSecretKey, nil
	})
	if err != nil || !token.Valid {
		return "", fmt.Errorf("invalid refresh token")
	}

	// Extract the application ID from the refresh token
	claims, ok := token.Claims.(*RefreshTokenClaims)
	if !ok {
		return "", fmt.Errorf("invalid token claims")
	}

	// Create a new access token with a shorter expiry time (e.g., 15 minutes)
	accessTokenClaims := AccessTokenClaims{
		ApplicationID: claims.ApplicationID,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
		},
	}

	// Create a new token object
	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessTokenClaims)

	// Sign the token with the access secret key
	signedAccessToken, err := accessToken.SignedString(accessSecretKey)
	if err != nil {
		return "", err
	}

	return signedAccessToken, nil
}

func ValidateAccessToken(accessToken string) (string, error) {
	// Parse and validate the access token
	token, err := jwt.ParseWithClaims(accessToken, &AccessTokenClaims{}, func(token *jwt.Token) (interface{}, error) {
		return accessSecretKey, nil
	})
	if err != nil || !token.Valid {
		return "", fmt.Errorf("invalid access token")
	}

	// Extract the application ID from the access token
	claims, ok := token.Claims.(*AccessTokenClaims)
	if !ok {
		return "", fmt.Errorf("invalid token claims")
	}

	// Return the application ID
	return claims.ApplicationID, nil
}

func TestRefreshTokens() {
	// Generate a refresh token
	refreshToken, err := GenerateRefreshToken("app_12345")
	if err != nil {
		log.Fatal("Error generating refresh token:", err)
	}
	fmt.Println("Refresh Token:", refreshToken)

	// Generate an access token from the refresh token
	accessToken, err := GenerateAccessTokenFromRefreshToken(refreshToken)
	if err != nil {
		log.Fatal("Error generating access token:", err)
	}
	fmt.Println("Access Token:", accessToken)

	// Validate the access token and get the application ID
	appID, err := ValidateAccessToken(accessToken)
	if err != nil {
		log.Fatal("Error validating access token:", err)

	}
	fmt.Println("Valid Access Token belongs to Application ID:", appID)
}