Skip to content

Commit

Permalink
Add the ability to logout with a token (#435)
Browse files Browse the repository at this point in the history
  • Loading branch information
dorsha authored May 7, 2024
1 parent 071b363 commit 19e0e2e
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
20 changes: 20 additions & 0 deletions descope/internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ func (auth *authenticationService) WebAuthn() sdk.WebAuthn {
}

func (auth *authenticationService) Logout(request *http.Request, w http.ResponseWriter) error {
return auth.logout(request, w)
}

func (auth *authenticationService) LogoutWithToken(refreshToken string, w http.ResponseWriter) error {
request := &http.Request{Header: http.Header{}}
request.AddCookie(&http.Cookie{Name: descope.RefreshCookieName, Value: refreshToken})
return auth.logout(request, w)
}

func (auth *authenticationService) logout(request *http.Request, w http.ResponseWriter) error {
if request == nil {
return utils.NewInvalidArgumentError("request")
}
Expand Down Expand Up @@ -153,6 +163,16 @@ func (auth *authenticationService) Logout(request *http.Request, w http.Response
}

func (auth *authenticationService) LogoutAll(request *http.Request, w http.ResponseWriter) error {
return auth.logoutAll(request, w)
}

func (auth *authenticationService) LogoutAllWithToken(refreshToken string, w http.ResponseWriter) error {
request := &http.Request{Header: http.Header{}}
request.AddCookie(&http.Cookie{Name: descope.RefreshCookieName, Value: refreshToken})
return auth.logoutAll(request, w)
}

func (auth *authenticationService) logoutAll(request *http.Request, w http.ResponseWriter) error {
if request == nil {
return utils.NewInvalidArgumentError("request")
}
Expand Down
52 changes: 52 additions & 0 deletions descope/internal/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,32 @@ func TestLogout(t *testing.T) {
require.NoError(t, err)
}

func TestLogoutWithToken(t *testing.T) {
a, err := newTestAuth(nil, func(r *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString(mockAuthSessionBody))}, nil
})
require.NoError(t, err)

w := httptest.NewRecorder()
err = a.LogoutWithToken(jwtRTokenValid, w)
strictCookies(t, w)
require.NoError(t, err)
require.Len(t, w.Result().Cookies(), 2)
c1 := w.Result().Cookies()[0]
assert.Empty(t, c1.Value)
assert.EqualValues(t, descope.SessionCookieName, c1.Name)
assert.EqualValues(t, "/my-path", c1.Path)
assert.EqualValues(t, "my-domain", c1.Domain)
c2 := w.Result().Cookies()[1]
assert.Empty(t, c2.Value)
assert.EqualValues(t, descope.RefreshCookieName, c2.Name)
assert.EqualValues(t, "/my-path", c2.Path)
assert.EqualValues(t, "my-domain", c2.Domain)

err = a.LogoutWithToken(jwtRTokenValid, nil)
require.NoError(t, err)
}

func TestLogoutAll(t *testing.T) {
a, err := newTestAuth(nil, func(r *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString(mockAuthSessionBody))}, nil
Expand Down Expand Up @@ -678,6 +704,32 @@ func TestLogoutAll(t *testing.T) {
require.NoError(t, err)
}

func TestLogoutAllWithToken(t *testing.T) {
a, err := newTestAuth(nil, func(r *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString(mockAuthSessionBody))}, nil
})
require.NoError(t, err)

w := httptest.NewRecorder()
err = a.LogoutAllWithToken(jwtRTokenValid, w)
strictCookies(t, w)
require.NoError(t, err)
require.Len(t, w.Result().Cookies(), 2)
c1 := w.Result().Cookies()[0]
assert.Empty(t, c1.Value)
assert.EqualValues(t, descope.SessionCookieName, c1.Name)
assert.EqualValues(t, "/my-path", c1.Path)
assert.EqualValues(t, "my-domain", c1.Domain)
c2 := w.Result().Cookies()[1]
assert.Empty(t, c2.Value)
assert.EqualValues(t, descope.RefreshCookieName, c2.Name)
assert.EqualValues(t, "/my-path", c2.Path)
assert.EqualValues(t, "my-domain", c2.Domain)

err = a.LogoutAllWithToken(jwtRTokenValid, nil)
require.NoError(t, err)
}

func TestLogoutNoClaims(t *testing.T) {
a, err := newTestAuth(nil, func(r *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: http.StatusOK}, nil
Expand Down
9 changes: 9 additions & 0 deletions descope/sdk/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,20 @@ type Authentication interface {
// Use the ResponseWriter (optional) to apply the cookies to the response automatically.
Logout(request *http.Request, w http.ResponseWriter) error

// LogoutWithToken - Logs out from the current session and deletes the session and refresh cookies in the http response.
// Use the ResponseWriter (optional) to apply the cookies to the response automatically.
LogoutWithToken(refreshToken string, w http.ResponseWriter) error

// LogoutAll - Use to perform logout from all active sessions for the request user. This will revoke the given tokens
// and if given options will also remove existing session on the given response sent to the client.
// Use the ResponseWriter (optional) to apply the cookies to the response automatically.
LogoutAll(request *http.Request, w http.ResponseWriter) error

// LogoutAllWithToken - Use to perform logout from all active sessions for the request user. This will revoke the given tokens
// and if given options will also remove existing session on the given response sent to the client.
// Use the ResponseWriter (optional) to apply the cookies to the response automatically.
LogoutAllWithToken(refreshToken string, w http.ResponseWriter) error

// Me - Use to retrieve current session user details. The request requires a valid refresh token.
// returns the user details or error if the refresh token is not valid.
Me(request *http.Request) (*descope.UserResponse, error)
Expand Down
20 changes: 20 additions & 0 deletions descope/tests/mocks/auth/authenticationmock.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,15 @@ type MockSession struct {
LogoutAssert func(r *http.Request, w http.ResponseWriter)
LogoutError error

LogoutWithTokenAssert func(refreshToken string, w http.ResponseWriter)
LogoutWithTokenError error

LogoutAllAssert func(r *http.Request, w http.ResponseWriter)
LogoutAllError error

LogoutAllWithTokenAssert func(refreshToken string, w http.ResponseWriter)
LogoutAllWithTokenError error

MeAssert func(r *http.Request)
MeError error
MeResponse *descope.UserResponse
Expand Down Expand Up @@ -801,13 +807,27 @@ func (m *MockSession) Logout(r *http.Request, w http.ResponseWriter) error {
return m.LogoutError
}

func (m *MockSession) LogoutWithToken(refreshToken string, w http.ResponseWriter) error {
if m.LogoutWithTokenAssert != nil {
m.LogoutWithTokenAssert(refreshToken, w)
}
return m.LogoutWithTokenError
}

func (m *MockSession) LogoutAll(r *http.Request, w http.ResponseWriter) error {
if m.LogoutAllAssert != nil {
m.LogoutAllAssert(r, w)
}
return m.LogoutAllError
}

func (m *MockSession) LogoutAllWithToken(refreshToken string, w http.ResponseWriter) error {
if m.LogoutAllWithTokenAssert != nil {
m.LogoutAllWithTokenAssert(refreshToken, w)
}
return m.LogoutAllWithTokenError
}

func (m *MockSession) Me(r *http.Request) (*descope.UserResponse, error) {
if m.MeAssert != nil {
m.MeAssert(r)
Expand Down

0 comments on commit 19e0e2e

Please sign in to comment.