Skip to content

Commit

Permalink
add logout route + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
juancwu committed Dec 23, 2024
1 parent 411372b commit 9172f13
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 2 deletions.
70 changes: 68 additions & 2 deletions backend/internal/tests/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"KonferCA/SPUR/internal/jwt"
"KonferCA/SPUR/internal/server"
"KonferCA/SPUR/internal/v1/v1_auth"
"KonferCA/SPUR/internal/v1/v1_common"
"KonferCA/SPUR/internal/v1/v1_common"

"bytes"
"context"
"encoding/json"
Expand Down Expand Up @@ -448,5 +448,71 @@ func TestServer(t *testing.T) {
assert.Equal(t, v1_common.ErrorTypeBadRequest, apiErr.Type)
assert.Equal(t, "Failed to verify email. Invalid or expired token.", apiErr.Message)
})

t.Run("/api/v1/auth/logout - 200 OK - successfully logout", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()

// register user
email := "[email protected]"
password := "mypassword123"
authReq := v1_auth.AuthRequest{
Email: email,
Password: password,
}
data, err := json.Marshal(authReq)
assert.NoError(t, err)
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/register", bytes.NewReader(data))
req.Header.Add(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()

s.Echo.ServeHTTP(rec, req)
assert.Equal(t, http.StatusCreated, rec.Code)
defer removeTestUser(ctx, email, s)

// get the cookie
cookies := rec.Result().Cookies()
var tokenCookie *http.Cookie
for _, cookie := range cookies {
if cookie.Name == v1_auth.COOKIE_REFRESH_TOKEN {
tokenCookie = cookie
break
}
}
if tokenCookie == nil {
t.Fatal("Refresh token cookie not found")
}
assert.NoError(t, err)
assert.NotNil(t, tokenCookie)
assert.NotEmpty(t, tokenCookie.Value)

req = httptest.NewRequest(http.MethodGet, "/api/v1/auth/logout", nil)
req.AddCookie(tokenCookie)
rec = httptest.NewRecorder()

s.Echo.ServeHTTP(rec, req)

assert.Equal(t, http.StatusOK, rec.Code)

// make sure the cookie value has been unset
tokenCookie = nil
cookies = rec.Result().Cookies()
for _, cookie := range cookies {
if cookie.Name == v1_auth.COOKIE_REFRESH_TOKEN {
tokenCookie = cookie
break
}
}
if tokenCookie == nil {
t.Fatal("Refresh token cookie not found")
}
assert.NoError(t, err)
assert.NotNil(t, tokenCookie)
assert.Empty(t, tokenCookie.Value)
// make sure the expiration date is less than right now
// and max-age is negative to indicate the browser to remove the cookie
assert.True(t, time.Now().After(tokenCookie.Expires))
assert.Equal(t, -1, tokenCookie.MaxAge)
})
})
}
8 changes: 8 additions & 0 deletions backend/internal/v1/v1_auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,11 @@ func (h *Handler) handleVerifyCookie(c echo.Context) error {
},
})
}

/*
Handle incoming logout requests. This will empty out the refresh token cookie.
*/
func (h *Handler) handleLogout(c echo.Context) error {
unsetRefreshTokenCookie(c)
return v1_common.Success(c, http.StatusOK, "Successfully logged out.")
}
13 changes: 13 additions & 0 deletions backend/internal/v1/v1_auth/cookies.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,16 @@ func setRefreshTokenCookie(c echo.Context, value string) {
cookie.Value = value
c.SetCookie(cookie)
}

/*
Unsets the refresh token cookie. Make the right configuration
that tells the browser to remove the cookie.
*/
func unsetRefreshTokenCookie(c echo.Context) {
cookie := getRefreshTokenCookieConfig()
cookie.Value = ""
// expires and max-age tells the browser to remove the cookie
cookie.Expires = time.Now().UTC()
cookie.MaxAge = -1
c.SetCookie(cookie)
}
1 change: 1 addition & 0 deletions backend/internal/v1/v1_auth/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ func SetupAuthRoutes(e *echo.Group, s interfaces.CoreServer) {
e.GET("/auth/verify", h.handleVerifyCookie)
e.GET("/auth/verify-email", h.handleVerifyEmail, authLimiter.RateLimit())
e.POST("/auth/register", h.handleRegister, authLimiter.RateLimit())
e.GET("/auth/logout", h.handleLogout, authLimiter.RateLimit())
}

0 comments on commit 9172f13

Please sign in to comment.