diff --git a/router/oauth2.go b/router/oauth2.go index 96574895c..b4760ec19 100644 --- a/router/oauth2.go +++ b/router/oauth2.go @@ -759,6 +759,31 @@ func (h *Handlers) tokenEndpointRefreshTokenHandler(c echo.Context) error { return c.JSON(http.StatusOK, res) } +// RevokeTokenEndpointHandler トークン無効化エンドポイントのハンドラ +func (h *Handlers) RevokeTokenEndpointHandler(c echo.Context) error { + var req struct { + Token string `form:"token"` + } + if err := c.Bind(&req); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + + if len(req.Token) == 0 { + return c.NoContent(http.StatusOK) + } + + if err := h.Repo.DeleteTokenByAccess(req.Token); err != nil { + h.requestContextLogger(c).Error(unexpectedError, zap.Error(err)) + return echo.NewHTTPError(http.StatusInternalServerError) + } + if err := h.Repo.DeleteTokenByRefresh(req.Token); err != nil { + h.requestContextLogger(c).Error(unexpectedError, zap.Error(err)) + return echo.NewHTTPError(http.StatusInternalServerError) + } + + return c.NoContent(http.StatusOK) +} + // SplitAndValidateScope スペース区切りのスコープ文字列を分解し、検証します func SplitAndValidateScope(str string) (model.AccessScopes, error) { var scopes model.AccessScopes diff --git a/router/oauth2_test.go b/router/oauth2_test.go index 17388ae63..c77ed5d8a 100644 --- a/router/oauth2_test.go +++ b/router/oauth2_test.go @@ -1935,3 +1935,47 @@ func TestHandlers_TokenEndpointAuthorizationCodeHandler(t *testing.T) { assert.EqualError(t, err, repository.ErrNotFound.Error()) }) } + +func TestHandlers_RevokeTokenEndpointHandler(t *testing.T) { + t.Parallel() + repo, server, _, _, _, _, user, _ := setupWithUsers(t, common6) + + t.Run("NoToken", func(t *testing.T) { + t.Parallel() + e := makeExp(t, server) + e.POST("/api/1.0/oauth2/revoke"). + WithFormField("token", ""). + Expect(). + Status(http.StatusOK) + }) + + t.Run("AccessToken", func(t *testing.T) { + t.Parallel() + token, err := repo.IssueToken(nil, user.ID, "", model.AccessScopes{}, 10000, false) + require.NoError(t, err) + + e := makeExp(t, server) + e.POST("/api/1.0/oauth2/revoke"). + WithFormField("token", token.AccessToken). + Expect(). + Status(http.StatusOK) + + _, err = repo.GetTokenByID(token.ID) + assert.EqualError(t, err, repository.ErrNotFound.Error()) + }) + + t.Run("RefreshToken", func(t *testing.T) { + t.Parallel() + token, err := repo.IssueToken(nil, user.ID, "", model.AccessScopes{}, 10000, true) + require.NoError(t, err) + + e := makeExp(t, server) + e.POST("/api/1.0/oauth2/revoke"). + WithFormField("token", token.RefreshToken). + Expect(). + Status(http.StatusOK) + + _, err = repo.GetTokenByID(token.ID) + assert.EqualError(t, err, repository.ErrNotFound.Error()) + }) +} diff --git a/router/router.go b/router/router.go index 7b472e79b..54507b568 100644 --- a/router/router.go +++ b/router/router.go @@ -274,6 +274,7 @@ func SetupRouting(e *echo.Echo, h *Handlers) { apiOAuth.GET("/authorize", h.AuthorizationEndpointHandler) apiOAuth.POST("/authorize", h.AuthorizationEndpointHandler) apiOAuth.POST("/token", h.TokenEndpointHandler) + apiOAuth.POST("/revoke", h.RevokeTokenEndpointHandler) } }