The refreshtoken no longer cares about when a token expired. When they want a new jtw from refresh a new refresh token is made also

This commit is contained in:
James Tombleson 2024-04-21 10:27:56 -07:00
parent b02ed3f86a
commit e7f706b6e7
5 changed files with 35 additions and 26 deletions

View File

@ -15,7 +15,6 @@ type RefreshTokenEntity struct {
Id int64 Id int64
Username string Username string
Token string Token string
ExpiresAt time.Time
CreatedAt time.Time CreatedAt time.Time
LastUpdated time.Time LastUpdated time.Time
} }

View File

@ -5,7 +5,6 @@ CREATE TABLE RefreshTokens (
ID INTEGER PRIMARY KEY AUTOINCREMENT, ID INTEGER PRIMARY KEY AUTOINCREMENT,
Username TEXT NOT NULL, Username TEXT NOT NULL,
Token TEXT NOT NULL, Token TEXT NOT NULL,
ExpiresAt DATETIME NOT NULL,
CreatedAt DATETIME NOT NULL, CreatedAt DATETIME NOT NULL,
LastUpdated DATETIME NOT NULL LastUpdated DATETIME NOT NULL
) )

View File

@ -15,7 +15,7 @@ const (
) )
type RefreshTokenTable interface { type RefreshTokenTable interface {
Create(username string, token string, expiresAt time.Time) (int64, error) Create(username string, token string) (int64, error)
GetByUsername(name string) (domain.RefreshTokenEntity, error) GetByUsername(name string) (domain.RefreshTokenEntity, error)
DeleteById(id int64) (int64, error) DeleteById(id int64) (int64, error)
} }
@ -30,12 +30,12 @@ func NewRefreshTokenRepository(conn *sql.DB) RefreshTokenRepository {
} }
} }
func (rt RefreshTokenRepository) Create(username string, token string, expiresAt time.Time) (int64, error) { func (rt RefreshTokenRepository) Create(username string, token string) (int64, error) {
dt := time.Now() dt := time.Now()
builder := sqlbuilder.NewInsertBuilder() builder := sqlbuilder.NewInsertBuilder()
builder.InsertInto(refreshTokenTableName) builder.InsertInto(refreshTokenTableName)
builder.Cols("Username", "Token", "ExpiresAt", "CreatedAt", "LastUpdated") builder.Cols("Username", "Token", "CreatedAt", "LastUpdated")
builder.Values(username, token, expiresAt, dt, dt) builder.Values(username, token, dt, dt)
query, args := builder.Build() query, args := builder.Build()
_, err := rt.connection.Exec(query, args...) _, err := rt.connection.Exec(query, args...)
@ -89,11 +89,10 @@ func (rd RefreshTokenRepository) processRows(rows *sql.Rows) []domain.RefreshTok
var id int64 var id int64
var username string var username string
var token string var token string
var expiresAt time.Time
var createdAt time.Time var createdAt time.Time
var lastUpdated time.Time var lastUpdated time.Time
err := rows.Scan(&id, &username, &token, &expiresAt, &createdAt, &lastUpdated) err := rows.Scan(&id, &username, &token, &createdAt, &lastUpdated)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -102,7 +101,6 @@ func (rd RefreshTokenRepository) processRows(rows *sql.Rows) []domain.RefreshTok
Id: id, Id: id,
Username: username, Username: username,
Token: token, Token: token,
ExpiresAt: expiresAt,
CreatedAt: createdAt, CreatedAt: createdAt,
LastUpdated: lastUpdated, LastUpdated: lastUpdated,
}) })

View File

@ -3,7 +3,6 @@ package repositories_test
import ( import (
"database/sql" "database/sql"
"testing" "testing"
"time"
"git.jamestombleson.com/jtom38/go-cook/internal/repositories" "git.jamestombleson.com/jtom38/go-cook/internal/repositories"
_ "github.com/glebarez/go-sqlite" _ "github.com/glebarez/go-sqlite"
@ -18,7 +17,7 @@ func TestRefreshTokenCreate(t *testing.T) {
} }
client := repositories.NewRefreshTokenRepository(conn) client := repositories.NewRefreshTokenRepository(conn)
rows, err := client.Create("tester", "BadTokenDontUse", time.Now().Add(time.Hour+1)) rows, err := client.Create("tester", "BadTokenDontUse")
if err != nil { if err != nil {
t.Log(err) t.Log(err)
t.FailNow() t.FailNow()
@ -37,7 +36,7 @@ func TestRefreshTokenGetByUsername(t *testing.T) {
} }
client := repositories.NewRefreshTokenRepository(conn) client := repositories.NewRefreshTokenRepository(conn)
rows, err := client.Create("tester", "BadTokenDoNotUse", time.Now().Add(time.Hour+1)) rows, err := client.Create("tester", "BadTokenDoNotUse")
if err != nil { if err != nil {
t.Log(err) t.Log(err)
t.FailNow() t.FailNow()
@ -68,7 +67,7 @@ func TestRefreshTokenDeleteById(t *testing.T) {
} }
client := repositories.NewRefreshTokenRepository(conn) client := repositories.NewRefreshTokenRepository(conn)
_, err = client.Create("tester", "BadTokenDoNotUse", time.Now().Add(time.Hour+1)) _, err = client.Create("tester", "BadTokenDoNotUse")
if err != nil { if err != nil {
t.Log(err) t.Log(err)
t.FailNow() t.FailNow()

View File

@ -3,20 +3,25 @@ package services
import ( import (
"database/sql" "database/sql"
"errors" "errors"
"time"
"git.jamestombleson.com/jtom38/go-cook/internal/domain" "git.jamestombleson.com/jtom38/go-cook/internal/domain"
"git.jamestombleson.com/jtom38/go-cook/internal/repositories" "git.jamestombleson.com/jtom38/go-cook/internal/repositories"
"github.com/google/uuid" "github.com/google/uuid"
) )
const (
ErrUnexpectedAmountOfRowsUpdated = "got a unexpected of rows updated"
)
type RefreshToken interface { type RefreshToken interface {
Create(username string, expiresAt time.Time) (string, error) Create(username string) (string, error)
GetByName(name string) (domain.RefreshTokenEntity, error) GetByName(name string) (domain.RefreshTokenEntity, error)
Delete(id int64) (int64, error) Delete(id int64) (int64, error)
IsRequestValid(username, refreshToken string, jwtExpiresAt time.Time) error IsRequestValid(username, refreshToken string) error
} }
// A new jwt token can be made if the user has the correct refresh token for the user.
// It will also require the old JWT token so the expire time is pulled and part of the validation
type RefreshTokenService struct { type RefreshTokenService struct {
table repositories.RefreshTokenTable table repositories.RefreshTokenTable
} }
@ -27,13 +32,26 @@ func NewRefreshTokenService(conn *sql.DB) RefreshTokenService {
} }
} }
func (rt RefreshTokenService) Create(username string, expiresAt time.Time) (string, error) { func (rt RefreshTokenService) Create(username string) (string, error) {
//if a refresh token already exists for a user, reuse
existingToken, err := rt.GetByName(username)
if err == nil {
rowsRemoved, err := rt.Delete(existingToken.Id)
if err != nil {
return "", err
}
if rowsRemoved != 1 {
return "", errors.New(ErrUnexpectedAmountOfRowsUpdated)
}
}
token, err := uuid.NewV7() token, err := uuid.NewV7()
if err != nil { if err != nil {
return "", err return "", err
} }
rows, err := rt.table.Create(username, token.String(), expiresAt) rows, err := rt.table.Create(username, token.String())
if err != nil { if err != nil {
return "", err return "", err
} }
@ -54,19 +72,15 @@ func (rt RefreshTokenService) Delete(id int64) (int64, error) {
return rt.table.DeleteById(id) return rt.table.DeleteById(id)
} }
func (rt RefreshTokenService) IsRequestValid(username, refreshToken string, jwtExpiresAt time.Time) error { func (rt RefreshTokenService) IsRequestValid(username, refreshToken string) error {
token, err := rt.GetByName(username) token, err := rt.GetByName(username)
if err != nil { if err != nil {
return err return err
} }
if (token.Token != refreshToken) { if token.Token != refreshToken {
return errors.New("the refresh token given does not match") return errors.New("the refresh token given does not match")
} }
if (token.ExpiresAt != jwtExpiresAt) {
return errors.New("the time when the jwt token expires does not match what was given")
}
return nil return nil
} }