Access Manager v3 API for C SDK
Access Manager v3 lets your servers grant PubNub clients time-limited tokens with embedded permissions, instead of exposing your keyset directly. A single pubnub_grant_token() call can cover any mix of resource types:
channelsgroups(channel groups)uuids(other users' App Context metadata)categories(list allchanneloruuidmetadata on the subscribe key, not one named resource)
each granted either by exact resource name or by a RegEx pattern, with different permission levels per resource, all in one request. A token can be restricted to a single client through authorized_uuid and always carries a ttl after which it stops working.
Access Manager is compiled in only when the SDK is built with PUBNUB_ENABLE_PAM, which itself requires PUBNUB_ENABLE_CRYPTO:
PUBNUB_ENABLE_PAM requires PUBNUB_ENABLE_CRYPTO
Access Manager's request signing depends on the crypto provider. A build configured with PUBNUB_ENABLE_PAM=ON and PUBNUB_ENABLE_CRYPTO=OFF fails at CMake configure time with a fatal error, before any source file compiles. Enable PUBNUB_ENABLE_CRYPTO in every build that enables PUBNUB_ENABLE_PAM.
Requires Secret Key authentication
Granting permissions to resources should be done by administrators whose SDK instance has been initialized with a Secret Key (available on the Admin Portal on your app's keyset).
Secure your secret_key
Anyone who has your secret_key can grant and revoke permissions on every resource in your app. Never let secret_key be discovered, never place it in client-side code, and deliver it to your servers only over a secure channel. Once a context has a non-empty secret_key and the build enables PUBNUB_ENABLE_PAM, the SDK automatically signs every request that context sends. This includes grant, revoke, and everything else. There is no separate function to call to sign a request, and no way to opt out of signing while secret_key is set.
Grant token
Requires Access Manager add-on
This function requires that the Access Manager add-on is enabled for your key in the Admin Portal. See Enable the features your app calls.
pubnub_grant_token() asks the server to issue a token with an embedded access-control list. Permissions are bits from pubnub_access_permission_t, OR'd together and attached to a resource name or pattern through pubnub_access_resource_permission_t.
Method(s)
#include <pubnub/features/access.h>
pubnub_future_t pubnub_grant_token(pubnub_context_t* ctx, const pubnub_grant_token_opts_t* opts);
pubnub_access_permission_t is a uint32_t type. The permission flags are PUBNUB_ACCESS_* macros that you combine with bitwise OR:
| Value | Numeric | Meaning |
|---|---|---|
PUBNUB_ACCESS_READ | 1 | Read messages and presence events. |
PUBNUB_ACCESS_WRITE | 2 | Publish messages. |
PUBNUB_ACCESS_MANAGE | 4 | Add or remove channels in channel groups. |
PUBNUB_ACCESS_DELETE | 8 | Delete messages from history. |
PUBNUB_ACCESS_CREATE | 16 | Create resources (App Context). |
PUBNUB_ACCESS_GET | 32 | Read resource metadata (App Context). |
PUBNUB_ACCESS_UPDATE | 64 | Update resource metadata (App Context). |
PUBNUB_ACCESS_JOIN | 128 | Join a channel (presence). |
These values match the wire format directly. For example, PUBNUB_ACCESS_READ combined with PUBNUB_ACCESS_WRITE serializes as 3. Not every bit is meaningful for every resource type. See Manage Permissions with Access Manager v3 for the resource-to-permission mapping the server enforces.
Each resource entry (pubnub_access_resource_permission_t):
| Parameter | Description |
|---|---|
nameType: const char* | Required, borrowed, NUL-terminated. An exact resource name, or a RegEx pattern string when the entry is placed in one of the pattern arrays below (for example "^chat\\..*$"). |
permissionsType: uint32_t | One or more pubnub_access_permission_t values, combined with bitwise OR. |
Grant options (pubnub_grant_token_opts_t):
| Parameter | Description |
|---|---|
ttl *Type: uint32_t | Minutes the token stays valid. Valid range is 1 to 43200 (30 days). 0 is rejected immediately with PUBNUB_ERR_INVALID_ARGUMENT, before any network call. There is no default. |
channelsType: const pubnub_access_resource_permission_t* | Exact channel permissions. |
channel_countType: size_t | Entries in channels. |
groupsType: const pubnub_access_resource_permission_t* | Exact channel-group permissions. |
group_countType: size_t | Entries in groups. |
uuidsType: const pubnub_access_resource_permission_t* | Exact uuid (App Context) permissions. |
uuid_countType: size_t | Entries in uuids. |
channel_patternsType: const pubnub_access_resource_permission_t* | RegEx pattern channel permissions. |
channel_pattern_countType: size_t | Entries in channel_patterns. |
group_patternsType: const pubnub_access_resource_permission_t* | RegEx pattern channel-group permissions. |
group_pattern_countType: size_t | Entries in group_patterns. |
uuid_patternsType: const pubnub_access_resource_permission_t* | RegEx pattern uuid permissions. |
uuid_pattern_countType: size_t | Entries in uuid_patterns. |
channels_category_permissionsType: uint32_t | Category permission for all channel metadata on the subscribe key. 0 (the default) grants nothing. If non-zero, the only valid value is PUBNUB_ACCESS_GET. |
uuids_category_permissionsType: uint32_t | Category permission for all uuid metadata on the subscribe key. 0 (the default) grants nothing. If non-zero, the only valid value is PUBNUB_ACCESS_GET. |
authorized_uuidType: const char* | Restricts the token to one client's uuid. Left NULL, the token can be used by any client that presents it. |
metaType: const char* | A JSON metadata string embedded in the token and readable back after parsing. |
timeout_msType: uint32_t | Per-request timeout override. When non-zero, takes priority over the context-level transaction_timeout_ms. |
PUBNUB_GRANT_TOKEN_OPTS_INIT zero-initializes every field, including ttl. Set ttl explicitly on every call, because the zero it starts at is itself an invalid value.
At least one permission is required
pubnub_grant_token() requires a permission on at least one resource, pattern, or category. A call where channels, groups, uuids, channel_patterns, group_patterns, uuid_patterns, channels_category_permissions, and uuids_category_permissions are all empty fails immediately with PUBNUB_ERR_INVALID_ARGUMENT.
C-family contract:
- Header —
#include <pubnub/features/access.h> - Types —
pubnub_grant_token_opts_t,pubnub_access_resource_permission_t,pubnub_access_permission_t - Prerequisite — a context created or initialized with
subscribe_key,publish_key, andsecret_keyset. See Identity and keys. - Feature flag — compiled in only when
PUBNUB_ENABLE_PAMis enabled. - Ownership / lifetime — every string and array field on
pubnub_grant_token_opts_tis borrowed. Thenamevalues insidechannels,groups,uuids, and the three pattern arrays, plusauthorized_uuidandmeta, must all remain valid untilpubnub_grant_token()returns. - Blocking — starts asynchronous work and returns a
pubnub_future_timmediately. Validation failures such as a missing or out-of-rangettl, no permissions, or missing keys come back as an already-failed future with no network call made.
Category permissions
A category permission covers a whole resource type instead of individual resources. Listing all channel or uuid metadata with App Context needs one, because a get on a single resource does not allow it. Set channels_category_permissions to PUBNUB_ACCESS_GET to allow listing all channel metadata, and uuids_category_permissions to PUBNUB_ACCESS_GET to allow listing all uuid metadata. Any other non-zero value makes pubnub_grant_token() return a future with PUBNUB_ERR_INVALID_ARGUMENT.
- A category permission lets a token list all metadata of one resource type on your subscribe key. Valid categories are
channelsanduuids. The only permission isget(32). - A
getpermission on one named channel or user, or on a pattern, does not grant a category. - A token can contain only categories. It needs no resource or pattern.
- When enumeration enforcement is enabled for a keyset, App Context list requests from a token or auth key without the matching category permission return a
403error.
Sample code
#include "pubnub/pubnub.h"
#include <stdio.h>
int main(void)
{
/* 1. Configure and create the client. secret_key is required for
Access Manager and must never be shipped in client-side code. */
pubnub_config_t cfg = pubnub_config_defaults();
cfg.publish_key = "demo";
cfg.subscribe_key = "demo";
cfg.secret_key = "demo";
cfg.user_id = "admin-user";
pubnub_context_t* ctx = pubnub_create(&cfg);
show all 63 linesReturns
pubnub_grant_token() returns a pubnub_future_t. Once pubnub_future_status() reports PUBNUB_OK, call pubnub_grant_token_result() to read the issued token:
| Parameter | Description |
|---|---|
tokenType: pubnub_string_view_t | The issued token. Valid until you call pubnub_future_release() on the future that produced it. Read or copy token.ptr/token.len before releasing. |
Other examples
Grant a token that lists all channel and uuid metadata
The code below grants a token the get category permission for both channels and uuids, with no resources.
1
Grant using an async callback
pubnub_grant_token() works the same way with any of the three future-consumption styles. This example uses pubnub_async() instead of cooperative polling:
#include "pubnub/pubnub.h"
#include <stdio.h>
static volatile int s_done;
static void on_grant(pubnub_future_t future, pubnub_res_t status, void* user_data)
{
(void)user_data;
if (PUBNUB_OK == status) {
pubnub_grant_token_result_t r = pubnub_grant_token_result(future);
printf("Token: %.*s\n", (int)r.token.len, r.token.ptr);
} else {
pubnub_string_view_t err = pubnub_response_error_message(future);
show all 67 linesError responses
Validation failures never reach the network. They come back as an already-failed future:
| Condition | Result |
|---|---|
opts is NULL | PUBNUB_ERR_INVALID_ARGUMENT |
ttl is 0 or exceeds 43200 | PUBNUB_ERR_INVALID_ARGUMENT |
| no permission set on any resource, pattern, or category | PUBNUB_ERR_INVALID_ARGUMENT |
a category permission other than 0 or PUBNUB_ACCESS_GET | PUBNUB_ERR_INVALID_ARGUMENT |
| the context or its configuration is invalid | PUBNUB_ERR_INVALID_ARGUMENT |
publish_key or secret_key is not set on the context | PUBNUB_ERR_INVALID_ARGUMENT |
| a required allocator/serialization provider is missing | PUBNUB_ERR_NOT_INITIALIZED |
| the request queue is full | PUBNUB_ERR_QUEUE_FULL |
| an internal allocation fails | PUBNUB_ERR_OUT_OF_MEMORY |
the platform provider's wall_clock_ms callback is missing or reports 0 (no RTC / not yet NTP-synchronized), so the Access Manager request cannot be timestamp-signed | PUBNUB_ERR_NO_WALL_CLOCK |
A server-side rejection completes the future with PUBNUB_ERR_SERVER. Call pubnub_response_service_error() to read the normalized detail. For Access Manager responses specifically, the resulting pubnub_service_error_t.source field is populated. It is empty for every other endpoint's error shape. See Retrieving server error detail.
Revoke token
Requires Access Manager add-on
This function requires that the Access Manager add-on, and specifically token revocation, is enabled for your key in the Admin Portal. Open your app's keyset and mark the Revoke v3 Token checkbox in the ACCESS MANAGER section.
pubnub_revoke_token() disables a token you previously issued with pubnub_grant_token(), invalidating every permission embedded in it. Use it only for tokens with a ttl of 30 days or less. For a longer-lived token, contact PubNub support.
Method(s)
#include <pubnub/features/access.h>
pubnub_future_t pubnub_revoke_token(pubnub_context_t* ctx, const pubnub_revoke_token_opts_t* opts);
Revoke options (pubnub_revoke_token_opts_t):
| Parameter | Description |
|---|---|
token *Type: const char* | Borrowed, NUL-terminated. The token to revoke. |
timeout_msType: uint32_t | Per-request timeout override, same semantics as grant's timeout_ms. |
PUBNUB_REVOKE_TOKEN_OPTS_INIT zero-initializes both fields. Set token explicitly before calling.
C-family contract:
- Header —
#include <pubnub/features/access.h> - Types —
pubnub_revoke_token_opts_t - Prerequisite — a context configured with
subscribe_keyandsecret_keyset. - Feature flag — compiled in only when
PUBNUB_ENABLE_PAMis enabled. - Ownership / lifetime —
tokenis borrowed and must remain valid untilpubnub_revoke_token()returns. - Blocking — starts asynchronous work and returns a
pubnub_future_timmediately. A missingtokenor missingsecret_keyfails immediately with no network call made.
Sample code
#include "pubnub/pubnub.h"
#include <stdio.h>
int main(void)
{
/* 1. Configure and create the client. */
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.secret_key = "demo";
cfg.user_id = "admin-user";
pubnub_context_t* ctx = pubnub_create(&cfg);
if (NULL == ctx) {
printf("pubnub_create failed\n");
show all 46 linesReturns
pubnub_revoke_token() returns a pubnub_future_t. There is no result struct. A successful revoke completes the future with PUBNUB_OK and nothing else to read.
Error responses
| Condition | Result |
|---|---|
opts is NULL | PUBNUB_ERR_INVALID_ARGUMENT |
token is NULL or empty | PUBNUB_ERR_INVALID_ARGUMENT |
| the context or its configuration is invalid | PUBNUB_ERR_INVALID_ARGUMENT |
secret_key is not set on the context | PUBNUB_ERR_INVALID_ARGUMENT |
A server-side rejection completes the future with PUBNUB_ERR_SERVER. Read the detail the same way as for Grant token. See Retrieving server error detail.
Parse token
pubnub_parse_token() decodes a token and exposes the permissions embedded in it. Use it for debugging, or to inspect a token received from a grant response or another source before deciding whether to use it.
This call is synchronous and local, not a network request
Unlike pubnub_grant_token() and pubnub_revoke_token(), pubnub_parse_token() returns a pubnub_res_t directly, not a pubnub_future_t. It decodes the token's base64url-encoded CBOR payload locally and never contacts the server.
Method(s)
#include <pubnub/features/access.h>
pubnub_res_t pubnub_parse_token(pubnub_context_t* ctx,
const pubnub_parse_token_opts_t* opts,
pubnub_parsed_token_t* out_result);
pubnub_parsed_token_resource_t pubnub_parsed_token_channel_at(pubnub_context_t* ctx, size_t index);
pubnub_parsed_token_resource_t pubnub_parsed_token_group_at(pubnub_context_t* ctx, size_t index);
pubnub_parsed_token_resource_t pubnub_parsed_token_uuid_at(pubnub_context_t* ctx, size_t index);
pubnub_parsed_token_resource_t pubnub_parsed_token_channel_pattern_at(pubnub_context_t* ctx, size_t index);
pubnub_parsed_token_resource_t pubnub_parsed_token_group_pattern_at(pubnub_context_t* ctx, size_t index);
pubnub_parsed_token_resource_t pubnub_parsed_token_uuid_pattern_at(pubnub_context_t* ctx, size_t index);
Parse options (pubnub_parse_token_opts_t):
| Parameter | Description |
|---|---|
token *Type: const char* | Borrowed, NUL-terminated. The base64url-encoded token string to decode. |
PUBNUB_PARSE_TOKEN_OPTS_INIT zero-initializes the struct. Set token explicitly.
C-family contract:
- Header —
#include <pubnub/features/access.h> - Types —
pubnub_parse_token_opts_t,pubnub_parsed_token_t,pubnub_parsed_token_resource_t - Prerequisite — none of the Access Manager keys are required. Parsing does not touch
secret_keyorpublish_key, and it does not make a request. - Feature flag — compiled in only when
PUBNUB_ENABLE_PAMis enabled. - Ownership / lifetime — the decoded resource data backing the six accessor functions lives on
ctx, not on yourout_result. It stays valid until the nextpubnub_parse_token()call on the same context, or untilpubnub_destroy()/pubnub_deinit(). The scalar fields you receive by value inout_result(version,timestamp,ttl,authorized_uuid, and the six*_countfields) are yours. Their*_countvalues, though, describe only that parse. Read them and call the accessors before parsing a second token on the same context. - Blocking — synchronous, local only. No network call, no future.
One parsed token per context
Calling pubnub_parse_token() again on the same context replaces the previously decoded data that the six indexed accessor functions read from. Your own out_result struct is unaffected, but its *_count fields become stale as loop bounds for the accessors once a second parse has happened on that context. Read everything you need, including every accessor call, from the first parse before parsing another token on the same ctx. The six accessors are not thread-safe against pubnub_parse_token() on the same context.
Sample code
#include "pubnub/pubnub.h"
#include <stdio.h>
int main(void)
{
/* 1. Configure and create the client. No secret_key is needed to parse. */
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "example-parse";
pubnub_context_t* ctx = pubnub_create(&cfg);
if (NULL == ctx) {
printf("pubnub_create failed\n");
return 1;
show all 77 linesThe code below reads the category permissions from a parsed token.
1
Returns
pubnub_parse_token() returns PUBNUB_OK on success and populates out_result (pubnub_parsed_token_t):
| Parameter | Description |
|---|---|
versionType: int32_t | Token format version. |
timestampType: uint64_t | Token creation time, Unix seconds. |
ttlType: uint32_t | Token time-to-live, in minutes, as embedded in the token. |
authorized_uuidType: pubnub_string_view_t | Empty (.len == 0) if the token was granted without an authorized_uuid restriction. |
channel_countType: uint32_t | Number of exact channel permissions. This bounds pubnub_parsed_token_channel_at(). |
group_countType: uint32_t | Number of exact channel-group permissions. This bounds pubnub_parsed_token_group_at(). |
uuid_countType: uint32_t | Number of exact uuid permissions. This bounds pubnub_parsed_token_uuid_at(). |
channel_pattern_countType: uint32_t | Number of pattern channel permissions. This bounds pubnub_parsed_token_channel_pattern_at(). |
group_pattern_countType: uint32_t | Number of pattern channel-group permissions. This bounds pubnub_parsed_token_group_pattern_at(). |
uuid_pattern_countType: uint32_t | Number of pattern uuid permissions. This bounds pubnub_parsed_token_uuid_pattern_at(). |
channels_category_permissionsType: uint32_t | PUBNUB_ACCESS_GET when the token carries the channels category permission, otherwise 0. |
uuids_category_permissionsType: uint32_t | PUBNUB_ACCESS_GET when the token carries the uuids category permission, otherwise 0. |
Each of the six indexed accessor functions returns a pubnub_parsed_token_resource_t:
| Parameter | Description |
|---|---|
nameType: pubnub_string_view_t | The resource name or pattern, aliasing data owned by ctx. See the ownership note above. |
permissionsType: uint32_t | The permission bits granted to this resource, as pubnub_access_permission_t values combined with bitwise OR. |
On failure, out_result is zero-initialized rather than left untouched.
Error responses
| Value | Meaning |
|---|---|
PUBNUB_OK | Decoded successfully. out_result is populated. |
PUBNUB_ERR_INVALID_ARGUMENT | opts->token is NULL or empty. |
PUBNUB_ERR_SERIALIZATION | The token is not valid base64url, or does not decode to a valid token structure. |
Set auth token
A client that receives a token attaches it to its own context with pubnub_set_auth_token() so that every subsequent request from that context carries the token. The token can come from your server's pubnub_grant_token_result_t.token, or from any other channel you use to deliver tokens. This function is declared in client.h, not access.h. The full pubnub_config_t/runtime-setter story, including pubnub_get_auth_token(), is documented in Runtime updates. This section covers only how it applies to a token received from Access Manager.
Method(s)
#include <pubnub/client.h>
pubnub_res_t pubnub_set_auth_token(pubnub_context_t* ctx, const char* token);
const char* pubnub_get_auth_token(const pubnub_context_t* ctx);
C-family contract:
- Header —
#include <pubnub/client.h> - Prerequisite — an already created or initialized context.
- Ownership / lifetime — on a
pubnub_create-based context,pubnub_set_auth_token()deep-copiestoken. On apubnub_init-based context, it borrows it.pubnub_get_auth_token()returns a context-owned pointer, valid until the nextpubnub_set_auth_token()call or context teardown. Do not free it. - Blocking — synchronous, no I/O.
This snippet is derived from the function declarations in client.h. There is no dedicated Access Manager example that exercises it.
Sample code
#include <pubnub/client.h>
static void apply_granted_token(pubnub_context_t* ctx, const char* token)
{
pubnub_res_t res = pubnub_set_auth_token(ctx, token);
if (PUBNUB_OK != res) {
/* token was rejected -- inspect res with pubnub_res_str() */
return;
}
const char* current = pubnub_get_auth_token(ctx);
(void)current;
}
Returns
pubnub_set_auth_token() returns PUBNUB_OK on success, PUBNUB_ERR_NOT_INITIALIZED if ctx is not initialized, or PUBNUB_ERR_OUT_OF_MEMORY if the deep-copy allocation fails (on pubnub_create-based contexts). pubnub_get_auth_token() returns the context's current auth_token, or NULL if none is set.