Repository: Nerzal/gocloak
Pull request #186 (2020-06-30 11:29:57)

Logout all sessions for a user
Thanks for your contribution!
Hi, if there is an issue, that your PR adresses, please link it! 



Patch:
diff --git a/README.md b/README.md
index 3c284d0..d86e453 100644
--- a/README.md
+++ b/README.md
@@ -109,6 +109,7 @@ type GoCloak interface {
 	LoginOtp(ctx context.Context, clientID, clientSecret, realm, username, password, totp string) (*JWT, error)
 	Logout(ctx context.Context, clientID, clientSecret, realm, refreshToken string) error
 	LogoutPublicClient(ctx context.Context, clientID, realm, accessToken, refreshToken string) error
+	LogoutAllSessions(ctx context.Context, accessToken, realm, userID string) error
 	LoginClient(ctx context.Context, clientID, clientSecret, realm string) (*JWT, error)
 	LoginClientSignedJWT(ctx context.Context, clientID, realm string, key interface{}, signedMethod jwt.SigningMethod, expiresAt int64) (*JWT, error)
 	LoginAdmin(ctx context.Context, username, password, realm string) (*JWT, error)
diff --git a/client.go b/client.go
index 43ace90..75994d2 100644
--- a/client.go
+++ b/client.go
@@ -474,6 +474,16 @@ func (client *gocloak) LogoutPublicClient(ctx context.Context, clientID, realm,
 	return checkForError(resp, err, errMessage)
 }
 
+// LogoutAllSessions logs out all sessions of a user given an id
+func (client *gocloak) LogoutAllSessions(ctx context.Context, accessToken, realm, userID string) error {
+	const errMessage = "could not logout"
+
+	resp, err := client.getRequestWithBearerAuth(ctx, accessToken).
+		Post(client.getAdminRealmURL(realm, "users", userID, "logout"))
+
+	return checkForError(resp, err, errMessage)
+}
+
 // ExecuteActionsEmail executes an actions email
 func (client *gocloak) ExecuteActionsEmail(ctx context.Context, token, realm string, params ExecuteActionsEmail) error {
 	const errMessage = "could not execute actions email"
diff --git a/go.mod b/go.mod
index 9a266eb..2347077 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module github.com/Nerzal/gocloak/v6
 go 1.14
 
 require (
-	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/go-resty/resty/v2 v2.3.0
 	github.com/pkg/errors v0.9.1
diff --git a/go.sum b/go.sum
index c075d4b..8c8177f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,5 @@
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/go-resty/resty/v2 v2.3.0 h1:JOOeAvjSlapTT92p8xiS19Zxev1neGikoHsXJeOq8So=
diff --git a/gocloak.go b/gocloak.go
index 5e0ccae..97a4ffe 100644
--- a/gocloak.go
+++ b/gocloak.go
@@ -26,6 +26,8 @@ type GoCloak interface {
 	Logout(ctx context.Context, clientID, clientSecret, realm, refreshToken string) error
 	// LogoutPublicClient sends a request to the logout endpoint using refresh token
 	LogoutPublicClient(ctx context.Context, clientID, realm, accessToken, refreshToken string) error
+	// LogoutAllSessions logs out all sessions of a user given an id
+	LogoutAllSessions(ctx context.Context, accessToken, realm, userID string) error
 	// LoginClient sends a request to the token endpoint using client credentials
 	LoginClient(ctx context.Context, clientID, clientSecret, realm string) (*JWT, error)
 	// LoginClientSignedJWT performs a login with client credentials and signed jwt claims


Test patch:
diff --git a/client_test.go b/client_test.go
index 791bac5..871a53c 100644
--- a/client_test.go
+++ b/client_test.go
@@ -1681,6 +1681,24 @@ func TestGocloak_Logout(t *testing.T) {
 	require.NoError(t, err, "Logout failed")
 }
 
+func TestGocloak_LogoutAllSessions(t *testing.T) {
+	t.Parallel()
+	cfg := GetConfig(t)
+	client := NewClientWithDebug(t)
+	token := GetAdminToken(t, client)
+
+	tearDown, userID := CreateUser(t, client)
+	defer tearDown()
+
+	err := client.LogoutAllSessions(
+		context.Background(),
+		token.AccessToken,
+		cfg.GoCloak.Realm,
+		userID,
+	)
+	require.NoError(t, err, "Logout failed")
+}
+
 func TestGocloak_GetRealm(t *testing.T) {
 	t.Parallel()
 	cfg := GetConfig(t)