---
source_url: https://www.pubnub.com/docs/security/access-control/manage-permissions
title: Grant, change, and revoke permissions
updated_at: 2026-10-13T08:57:28.000Z
---

# Grant, change, and revoke permissions

> For AI agents: documentation index at https://www.pubnub.com/llms-full.txt

Use a server-side PubNub instance initialized with a `secretKey` to grant time-limited tokens to your clients, update their permissions by issuing new tokens, and revoke tokens when access must be removed immediately.

## Before you start

Confirm you have:

* Access Manager enabled on your keyset. See [Configure access control](https://www.pubnub.com/docs/security/access-control/configure-access-control.md).
* A server-side PubNub instance initialized with a `secretKey`. See [Initialize a server SDK with a secret key](https://www.pubnub.com/docs/security/access-control/initialize-server-sdk.md).
* For token revocation: the **Revoke v3 Token** option enabled on the keyset. See [Configure access control](https://www.pubnub.com/docs/security/access-control/configure-access-control.md#enable-token-revocation).

## Grant a token

Call `grantToken` from your server. Specify the authorized User ID, the resource permissions, and the TTL.

The example below grants `my-authorized-uuid`:

* `read` on `channel-a`, `channel-group-b`, and `uuid-c`.
* `read` and `write` on `channel-b`, `channel-c`, `channel-d`, and `uuid-d`.
* `read` on all channels matching the RE2 pattern `^channel-[A-Za-z0-9]$`.

### JavaScript

```javascript
pubnub.grantToken(
    {
        ttl: 15,
        authorized_uuid: "my-authorized-uuid",
        resources: {
            channels: {
                "channel-a": { read: true },
                "channel-b": { read: true, write: true },
                "channel-c": { read: true, write: true },
                "channel-d": { read: true, write: true }
            },
            groups: {
                "channel-group-b": { read: true }
            },
            uuids: {
                "uuid-c": { get: true },
                "uuid-d": { get: true, update: true }
            }
        },
        patterns: {
            channels: {
                "^channel-[A-Za-z0-9]$": { read: true }
            }
        }
    },
    function (status, token) {
        console.log(token)
    });
```

### Python

```python
from pubnub.models.consumer.v3.channel import Channel
from pubnub.models.consumer.v3.group import Group
from pubnub.models.consumer.v3.uuid import UUID

channels = [
    Channel.id("channel-a").read(),
    Channel.pattern("channel-[A-Za-z0-9]").read(),
    Channel.id("channel-b").read().write(),
    Channel.id("channel-c").read().write(),
    Channel.id("channel-d").read().write()
]
channel_groups = [
    Group.id("channel-group-b").read()
]
uuids = [
    UUID.id("uuid-c").get(),
    UUID.id("uuid-d").get().update()
]
envelope = pubnub.grant_token() \
    .authorized_uuid("my-authorized-uuid") \
    .channels(channels) \
    .groups(channel_groups) \
    .uuids(uuids) \
    .ttl(15) \
    .sync()

token = envelope.result.token
```

### Java

```java
pubnub.grantToken()
    .ttl(15)
    .authorizedUUID("my-authorized-uuid")
    .channels(Arrays.asList(
            ChannelGrant.name("channel-a").read(),
            ChannelGrant.name("channel-b").read().write(),
            ChannelGrant.name("channel-c").read().write(),
            ChannelGrant.name("channel-d").read().write(),
            ChannelGrant.pattern("^channel-[A-Za-z0-9]*$").read()))
    .channelGroups(Collections.singletonList(
            ChannelGroupGrant.id("channel-group-b").read()))
    .uuids(Arrays.asList(
            UUIDGrant.id("uuid-c").get(),
            UUIDGrant.id("uuid-d").get().update()))
    .async(result -> { /* check result */ });
```

### Kotlin

```kotlin
pubnub.grantToken(
    ttl = 15,
    authorizedUUID = "my-authorized-uuid",
    channels = listOf(
        ChannelGrant.name(name = "channel-a", read = true),
        ChannelGrant.name(name = "channel-b", read = true, write = true),
        ChannelGrant.name(name = "channel-c", read = true, write = true),
        ChannelGrant.name(name = "channel-d", read = true, write = true),
        ChannelGrant.pattern(pattern = "^channel-[A-Za-z0-9]*$", read = true)
    ),
    channelGroups = listOf(
        ChannelGroupGrant.id(id = "channel-group-b", read = true)
    ),
    uuids = listOf(
        UUIDGrant.id(id = "uuid-c", get = true),
        UUIDGrant.id(id = "uuid-d", get = true, update = true)
    )
).sync()
```

### Go

```go
res, status, err := pn.GrantToken().
    TTL(15).
    AuthorizedUUID("my-authorized-uuid").
    Channels(map[string]pubnub.ChannelPermissions{
        "channel-a": { Read: true },
        "channel-b": { Read: true, Write: true },
        "channel-c": { Read: true, Write: true },
        "channel-d": { Read: true, Write: true },
    }).
    ChannelGroups(map[string]pubnub.GroupPermissions{
        "channel-group-b": { Read: true },
    }).
    UUIDs(map[string]pubnub.UUIDPermissions{
        "uuid-c": { Get: true },
        "uuid-d": { Get: true, Update: true },
    }).
    ChannelsPattern(map[string]pubnub.ChannelPermissions{
        "^channel-[A-Za-z0-9]*$": { Read: true },
    }).
    Execute()
```

### C-Core (legacy)

:::note New SDK available
C-Core (legacy) is still supported. If you are starting a new project, use the new [C SDK](https://www.pubnub.com/docs/sdks/c.md).
:::

```c
char* author_uuid = "my-authorized-uuid";
struct pam_permission cha_perm = {.read=true };
struct pam_permission cgb_perm = {.read=true };
struct pam_permission uidc_perm = {.get=true };
struct pam_permission chb_perm = {.read=true, .write=true };
struct pam_permission chc_perm = {.read=true, .write=true };
struct pam_permission chd_perm = {.read=true, .write=true };
struct pam_permission uidd_perm = {.get=true, .update=true };
struct pam_permission pat_ch_perm = {.read=true };

int perm_cha = pubnub_get_grant_bit_mask_value(cha_perm);
int perm_chb = pubnub_get_grant_bit_mask_value(chb_perm);
int perm_chc = pubnub_get_grant_bit_mask_value(chc_perm);
int perm_chd = pubnub_get_grant_bit_mask_value(chd_perm);
int perm_cgb = pubnub_get_grant_bit_mask_value(cgb_perm);
int perm_uidc = pubnub_get_grant_bit_mask_value(uidc_perm);
int perm_uidd = pubnub_get_grant_bit_mask_value(uidd_perm);
int perm_ch_pat = pubnub_get_grant_bit_mask_value(pat_ch_perm);

int ttl_minutes = 15;
char perm_obj[2000];
sprintf(perm_obj,"{\"ttl\":%d, \"uuid\":\"%s\", \"permissions\":{\"resources\":{\"channels\":{ \"channel-a\":%d, \"channel-b\":%d, \"channel-c\":%d, \"channel-d\":%d }, \"groups\":{ \"channel-group-b\":%d }, \"uuids\":{ \"uuid-c\":%d, \"uuid-d\":%d }}, \"patterns\":{\"channels\":{ \"channel-[A-Za-z0-9]\":%d }, \"groups\":{ }, \"uuids\":{ }},\"meta\":{ }}}", ttl_minutes, author_uuid, perm_cha, perm_chb, perm_chc, perm_chd, perm_cgb, perm_uidc, perm_uidd, perm_ch_pat);
res = pubnub_grant_token(gtp, perm_obj);
if (PNR_STARTED == res) {
    res = pubnub_await(gtp);
    if (PNR_OK == res) {
        pubnub_chamebl_t grant_token_resp = pubnub_get_grant_token(gtp);
        printf("pubnub_grant_token() Response from Pubnub: %s\n", grant_token_resp.ptr);
    }
}
```

### C#

```csharp
PNResult<PNAccessManagerTokenResult> grantTokenResponse = await pubnub.GrantToken()
    .TTL(15)
    .AuthorizedUuid("my-authorized-uuid")
    .Resources(new PNTokenResources()
    {
        Channels = new Dictionary<string, PNTokenAuthValues>() {
            { "channel-a", new PNTokenAuthValues() { Read = true } },
            { "channel-b", new PNTokenAuthValues() { Read = true, Write = true } },
            { "channel-c", new PNTokenAuthValues() { Read = true, Write = true } },
            { "channel-d", new PNTokenAuthValues() { Read = true, Write = true } }},
        ChannelGroups = new Dictionary<string, PNTokenAuthValues>() {
            { "channel-group-b", new PNTokenAuthValues() { Read = true } } },
        Uuids = new Dictionary<string, PNTokenAuthValues>() {
            { "uuid-c", new PNTokenAuthValues() { Get = true } },
            { "uuid-d", new PNTokenAuthValues() { Get = true, Update = true } }}
    })
    .Patterns(new PNTokenPatterns()
    {
        Channels = new Dictionary<string, PNTokenAuthValues>() {
            { "channel-[A-Za-z0-9]", new PNTokenAuthValues() { Read = true } }}
    })
    .ExecuteAsync();
PNAccessManagerTokenResult grantTokenResult = grantTokenResponse.Result;
PNStatus grantTokenStatus = grantTokenResponse.Status;
if (!grantTokenStatus.Error && grantTokenResult != null)
{
    Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(grantTokenResult));
}
else
{
    Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(grantTokenStatus));
}
```

### Dart

```dart
var request = pubnub.requestToken(
    ttl: 15, authorizedUUID: 'my-authorized-uuid')
..add(ResourceType.channel, name: 'channel-a', read: true)
..add(ResourceType.channelGroup, name: 'channel-group-b', read: true)
..add(ResourceType.uuid, name: 'uuid-c', get: true)
..add(ResourceType.channel, name: 'channel-b', read: true, write: true)
..add(ResourceType.channel, name: 'channel-c', read: true, write: true)
..add(ResourceType.channel, name: 'channel-d', read: true, write: true)
..add(ResourceType.uuid, name: 'uuid-d', get: true, update: true)
..add(ResourceType.channel, pattern: 'channel-[A-Za-z0-9]', read: true);

var token = await pubnub.grantToken(request);
print('grant token = $token');
```

### PHP

```php
$pubnub->grantToken()
    ->ttl(15)
    ->authorizedUuid('my-authorized-uuid')
    ->addChannelResources([
        'channel-a' => ['read' => true],
        'channel-b' => ['read' => true, 'write' => true],
        'channel-c' => ['read' => true, 'write' => true],
        'channel-d' => ['read' => true, 'write' => true],
    ])
    ->addChannelGroupResources([
        'channel-group-b' => ['read' => true],
    ])
    ->addUuidResources([
        'uuid-c' => ['get' => true],
        'uuid-d' => ['get' => true, 'update' => true],
    ])
    ->addChannelPatterns([
        '^channel-[A-Za-z0-9]$' => ['read' => true],
    ])
```

### Ruby

```ruby
pubnub.grant_token(
    ttl: 15,
    authorized_uuid: "my-authorized-uuid",
    channels: {
        "channel-a": Pubnub::Permissions.res(read: true),
        "channel-b": Pubnub::Permissions.res(read: true, write: true),
        "channel-c": Pubnub::Permissions.res(read: true, write: true),
        "channel-d": Pubnub::Permissions.res(read: true, write: true),
        "^channel-[A-Za-z0-9]$": Pubnub::Permission.pat(read: true)
    },
    channel_groups: {
        "channel-group-b": Pubnub::Permissions.res(read: true)
    },
    uuids: {
        "uuid-c": Pubnub::Permissions.res(get: true),
        "uuid-d": Pubnub::Permissions.res(get: true, update: true)
    },
    http_sync: true
);
```

:::note Authorized UUID vs UUIDs
The authorized user ID binds the token to one User ID that can use it. SDKs name this parameter `authorizedUserId` or `authorizedUuid`, and the token carries it as `authorized_uuid`. The `uuids` key inside `resources` grants permissions to access *other users'* metadata. These are different fields with different purposes.
:::

:::note Token size limit
Access Manager `grantToken()` requests over 32 KiB return HTTP 414 (URI Too Long). Prefer RE2 patterns over long resource lists, and keep resource names short.
:::

## Change permissions

To change a user's permissions, grant a new token with the updated resource list and return it to the client. The client sets the new token using `setToken` and uses it for subsequent calls.

To update a token on the client after receiving it, see [Initialize a client SDK with an auth key](https://www.pubnub.com/docs/security/access-control/initialize-client-sdk.md).

## Revoke a token

Revoking a token immediately blocks all requests that use it. A request that uses a revoked token fails with `403 Revoked Token`. Each revoke call accepts a single token, so batch revocation isn't supported.

:::note Revocation delay
Token revocation can take up to one minute to take effect, because PubNub caches a token's non-revoked state for that long.
A revoked token's deny-list entry persists until the token's original TTL would have expired.
A revoked token can't be re-enabled.
:::

### JavaScript

```javascript
const token = await pubnub.revokeToken("p0AkFl043rhDdHRsple3KgQ3NwY6BDcENnctokenVzcqBDczaWdYIGOAeTyWGJI");
```

### Python

```python
envelope = pubnub.revoke_token("p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV")
    .sync()
```

### Java

```java
pubnub.revokeToken()
    .token("p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV")
    .sync()
```

### Kotlin

```kotlin
pubnub.revokeToken("p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV")
    .sync()
```

### Go

```go
res, status, err := pn.RevokeToken().
    Token("p0thisAkFl043rhDdHRsCNlY3JldAFDZ3Jwsample3KgQ3NwY6BDENnctokenV").
    Execute()
```

### C#

```csharp
PNResult<PNAccessManagerRevokeTokenResult> revokeTokenResponse = await pubnub
    .RevokeToken()
    .Token("p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV")
    .ExecuteAsync();
PNAccessManagerRevokeTokenResult revokeTokenResult = revokeTokenResponse.Result;
PNStatus revokeTokenStatus = revokeTokenResponse.Status;
if (!revokeTokenStatus.Error && revokeTokenResult != null)
{
    Console.WriteLine("Revoke token success");
}
else
{
    Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(revokeTokenStatus));
}
```

### Dart

```dart
await pubnub.revokeToken("p0AkFl043rhDdHRsple3KgQ3NwY6BDcENnctokenVzcqBDczaWdYIGOAeTyWGJI");
```

### PHP

```php
$pubnub->revokeToken("p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV")
    ->sync();
```

### Ruby

```ruby
pubnub.revoke_token(token: "p0thisAkFl043rhDdHRsCkNyZXisRGNoYW6hanNlY3JldAFDZ3Jwsample3KgQ3NwY6BDcGF0pERjaGFuoENnctokenV", http_sync: true)
```

:::tip Debug Console
To generate or revoke a test token without writing code, use the **Access Manager** tab of the Debug Console in the [Admin Portal](https://admin.pubnub.com/).
:::

## Related pages

* [Initialize a client SDK with an auth key](https://www.pubnub.com/docs/security/access-control/initialize-client-sdk.md). Set the granted token on the client.
* [Check available permissions](https://www.pubnub.com/docs/security/access-control/check-permissions.md). Decode a token to inspect its embedded permissions.
* [Change or extend access](https://www.pubnub.com/docs/security/access-control/change-or-extend-access.md). Strategies for updating tokens before they expire.
* [Update an expired token](https://www.pubnub.com/docs/security/access-control/update-expired-token.md). Handle `403` errors when a token has expired.
* [Permission model](https://www.pubnub.com/docs/security/access-control/permission-model.md). Available permission flags per resource type.
* [Operations to permissions mapping](https://www.pubnub.com/docs/security/access-control/operations-permissions-mapping.md). Which permission each PubNub API operation requires.

Last updated at: 2026-10-13T08:57:28.000Z
