From 4f7935115337db9b49f6ea73ce2e70ca4e6c93ae Mon Sep 17 00:00:00 2001 From: Mateusz Wiktor Date: Fri, 23 Oct 2026 11:37:33 +0200 Subject: [PATCH 1/3] docs: add Access Manager categories snippets Add sync and asyncio examples with grant_token_categories, parse_token_categories and grant_categories snippets. Co-Authored-By: Claude Sonnet 5.5 --- .../native_sync/access_manager_categories.py | 87 ++++++++++++++++++ .../access_manager_categories_async.py | 91 +++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 examples/native_sync/access_manager_categories.py create mode 100644 examples/pubnub_asyncio/access_manager_categories_async.py diff --git a/examples/native_sync/access_manager_categories.py b/examples/native_sync/access_manager_categories.py new file mode 100644 index 00000000..39e336f6 --- /dev/null +++ b/examples/native_sync/access_manager_categories.py @@ -0,0 +1,87 @@ +import os +from typing import Dict +from pubnub.models.consumer.v3.category import Category +from pubnub.pnconfiguration import PNConfiguration +from pubnub.pubnub import PubNub + + +def initialize_pubnub() -> PubNub: + """ + Initialize a PubNub instance for a keyset with Access Manager enabled. + The secret key is required to grant permissions. + """ + pnconfig = PNConfiguration() + pnconfig.publish_key = os.getenv('PUBLISH_PAM_KEY', 'demo') + pnconfig.subscribe_key = os.getenv('SUBSCRIBE_PAM_KEY', 'demo') + pnconfig.secret_key = os.getenv('SECRET_PAM_KEY', 'demo') + pnconfig.user_id = 'my_admin' + return PubNub(pnconfig) + + +# snippet.grant_token_categories +def grant_token_categories(pubnub: PubNub) -> str: + """ + Grant a token that lets its holder list all channel metadata and all uuid metadata. + Category permissions support only the `get` operation. + + Args: + pubnub (PubNub): PubNub instance configured with a secret key + + Returns: + str: The granted token + """ + envelope = pubnub.grant_token() \ + .categories([Category.channels().get(), Category.uuids().get()]) \ + .authorized_uuid('my_authorized_uuid') \ + .ttl(15) \ + .sync() + return envelope.result.get_token() +# snippet.end + + +# snippet.parse_token_categories +def parse_token_categories(pubnub: PubNub, token: str) -> Dict: + """ + Parse a token and return its category permissions. + + Args: + pubnub (PubNub): PubNub instance + token (str): Token generated by grant_token + + Returns: + Dict: Category permissions, for example {'channels': {'get': True}, 'uuids': {'get': True}} + """ + parsed_token = pubnub.parse_token(token) + return parsed_token['categories'] +# snippet.end + + +# snippet.grant_categories +def grant_categories(pubnub: PubNub, auth_key: str) -> None: + """ + Grant an auth key permission to list all channel metadata and all uuid metadata. + This legacy grant method requires the secret key to be set on the client. + + Args: + pubnub (PubNub): PubNub instance configured with a secret key + auth_key (str): The auth key to grant permissions to + """ + envelope = pubnub.grant() \ + .auth_keys(auth_key) \ + .categories(['channels', 'uuids']) \ + .get(True) \ + .ttl(15) \ + .sync() + print(f"Granted category permissions, level: {envelope.result.level}") +# snippet.end + + +def main() -> None: + pubnub = initialize_pubnub() + token = grant_token_categories(pubnub) + print(f"Category permissions in token: {parse_token_categories(pubnub, token)}") + grant_categories(pubnub, 'my_auth_key') + + +if __name__ == '__main__': + main() diff --git a/examples/pubnub_asyncio/access_manager_categories_async.py b/examples/pubnub_asyncio/access_manager_categories_async.py new file mode 100644 index 00000000..bed0a7b7 --- /dev/null +++ b/examples/pubnub_asyncio/access_manager_categories_async.py @@ -0,0 +1,91 @@ +import asyncio +import os +from typing import Dict +from pubnub.models.consumer.v3.category import Category +from pubnub.pnconfiguration import PNConfiguration +from pubnub.pubnub_asyncio import PubNubAsyncio + + +def initialize_pubnub() -> PubNubAsyncio: + """ + Initialize a PubNub instance for a keyset with Access Manager enabled. + The secret key is required to grant permissions. + """ + pnconfig = PNConfiguration() + pnconfig.publish_key = os.getenv('PUBLISH_PAM_KEY', 'demo') + pnconfig.subscribe_key = os.getenv('SUBSCRIBE_PAM_KEY', 'demo') + pnconfig.secret_key = os.getenv('SECRET_PAM_KEY', 'demo') + pnconfig.user_id = 'my_admin' + return PubNubAsyncio(pnconfig) + + +# snippet.grant_token_categories +async def grant_token_categories(pubnub: PubNubAsyncio) -> str: + """ + Grant a token that lets its holder list all channel metadata and all uuid metadata. + Category permissions support only the `get` operation. + + Args: + pubnub (PubNubAsyncio): PubNub instance configured with a secret key + + Returns: + str: The granted token + """ + envelope = await pubnub.grant_token( + categories=[Category.channels().get(), Category.uuids().get()], + authorized_user_id='my_authorized_uuid', + ttl=15 + ).future() + return envelope.result.get_token() +# snippet.end + + +# snippet.parse_token_categories +def parse_token_categories(pubnub: PubNubAsyncio, token: str) -> Dict: + """ + Parse a token and return its category permissions. + + Args: + pubnub (PubNubAsyncio): PubNub instance + token (str): Token generated by grant_token + + Returns: + Dict: Category permissions, for example {'channels': {'get': True}, 'uuids': {'get': True}} + """ + parsed_token = pubnub.parse_token(token) + return parsed_token['categories'] +# snippet.end + + +# snippet.grant_categories +async def grant_categories(pubnub: PubNubAsyncio, auth_key: str) -> None: + """ + Grant an auth key permission to list all channel metadata and all uuid metadata. + This legacy grant method requires the secret key to be set on the client. + + Args: + pubnub (PubNubAsyncio): PubNub instance configured with a secret key + auth_key (str): The auth key to grant permissions to + """ + envelope = await pubnub.grant() \ + .auth_keys(auth_key) \ + .categories(['channels', 'uuids']) \ + .get(True) \ + .ttl(15) \ + .future() + print(f"Granted category permissions, level: {envelope.result.level}") +# snippet.end + + +async def main() -> None: + pubnub = initialize_pubnub() + try: + token = await grant_token_categories(pubnub) + print(f"Category permissions in token: {parse_token_categories(pubnub, token)}") + await grant_categories(pubnub, 'my_auth_key') + finally: + await pubnub.stop() + + +if __name__ == '__main__': + asyncio.run(main()) From 3f77e27e23cdd505e9c1f2e6c1bd54decdb83176 Mon Sep 17 00:00:00 2001 From: jguz-pubnub Date: Mon, 26 Oct 2026 09:38:33 +0100 Subject: [PATCH 2/3] Fix in requirements-dev.txt --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 722abcbe..34c9a6c6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,5 +11,5 @@ aiohttp>=3.10.11,<3.11 cbor2>=5.6 behave>=1.2.6 vcrpy>=6.0.2 -urllib3>=1.26.19,<2 +urllib3>=2.0 busypie>=0.5.1 From 4ab842192c67ac40c71b7119aee6705d83463c15 Mon Sep 17 00:00:00 2001 From: jguz-pubnub Date: Mon, 26 Oct 2026 09:43:21 +0100 Subject: [PATCH 3/3] Fix in requirements-dev.txt (2) --- requirements-dev.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 34c9a6c6..27b01f43 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,5 +11,6 @@ aiohttp>=3.10.11,<3.11 cbor2>=5.6 behave>=1.2.6 vcrpy>=6.0.2 -urllib3>=2.0 +urllib3>=1.26.19,<2; python_version < "3.10" +urllib3>=2.0; python_version >= "3.10" busypie>=0.5.1