From fa49317c2b6d732c02f80a83e2adf1c98e8a2865 Mon Sep 17 00:00:00 2001 From: Nick Stillman Date: Wed, 25 Feb 2026 17:42:38 -0500 Subject: [PATCH] #6 Add OAuth revoke (DELETE /api/token) --- CHANGELOG.rst | 1 + README.rst | 1 + berserk/clients/oauth.py | 19 ++++++++++++++++++- tests/clients/test_oauth.py | 17 +++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tests/clients/test_oauth.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a95bc88d..69539690 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ Changelog To be released -------------- +* Added ``client.oauth.revoke`` to revoke the access token (DELETE /api/token). * Deprecate Python 3.9 support - minimum required version is now Python 3.10+. This does not mean the library will not work with Python 3.9, but it will not be tested against it anymore. diff --git a/README.rst b/README.rst index c627f5e6..27549722 100644 --- a/README.rst +++ b/README.rst @@ -170,6 +170,7 @@ Most of the API is available: client.messaging.send + client.oauth.revoke client.oauth.test_tokens client.puzzles.get_daily diff --git a/berserk/clients/oauth.py b/berserk/clients/oauth.py index 6606b5fa..b7f58aac 100644 --- a/berserk/clients/oauth.py +++ b/berserk/clients/oauth.py @@ -1,12 +1,29 @@ from __future__ import annotations +from urllib.parse import urljoin + from typing import Any, Dict -from .. import models +from .. import exceptions, models from .base import BaseClient class OAuth(BaseClient): + def revoke(self) -> None: + """Revoke the access token sent as Bearer (DELETE /api/token). + + The session must be authenticated with the token to revoke (e.g. + ``TokenSession(access_token)``). After a successful call, the token + is invalid and must not be used for further requests. + + :return: None. Raises if the request fails. + """ + path = "/api/token" + url = urljoin(self._r.base_url, path) + response = self._r.session.request("DELETE", url) + if not response.ok: + raise exceptions.ResponseError(response) + def test_tokens(self, *tokens: str) -> Dict[str, Any]: """Test the validity of up to 1000 OAuth tokens. diff --git a/tests/clients/test_oauth.py b/tests/clients/test_oauth.py new file mode 100644 index 00000000..ab30757d --- /dev/null +++ b/tests/clients/test_oauth.py @@ -0,0 +1,17 @@ +import requests_mock + +import berserk + + +class TestOAuthRevoke: + def test_revoke_sends_delete_with_bearer_token(self): + """Verify the client sends DELETE /api/token with Authorization Bearer.""" + with requests_mock.Mocker() as m: + m.delete("https://lichess.org/api/token", status_code=204) + session = berserk.TokenSession("my_access_token") + client = berserk.Client(session=session) + client.oauth.revoke() + assert m.call_count == 1 + req = m.last_request + assert req.method == "DELETE" + assert req.headers.get("Authorization") == "Bearer my_access_token"