---
source_url: https://www.pubnub.com/docs/sdks/legacy-access-manager-signature-construction
title: Legacy Access Manager Signature Construction
updated_at: 2026-06-18T11:27:56.072Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Legacy Access Manager Signature Construction

The legacy Access Manager API accepts the `signature` query parameter as a way to authenticate that the request was indeed created by a client that has possession of the `secret-key`.

:::note Legacy signature scheme
The information on this page applies only to the legacy (deprecated) signature scheme. The current signature scheme for all PubNub REST APIs is described in [the Access Manager documentation](https://www.pubnub.com/docs/sdks/rest-api/access-manager-introduction).
:::

## Generating the signature body

The template of the signature body consists of the following order:

```javascript
{subscribe-key}
{publish-key}
{endpoint-url}
{GET query params}
```

The `GET query params` are a querystring representation of the GET query params with the following rules:

* GET query params parameters must be sorted lexicographically (case-sensitive) by key.
* Secondly, all characters in the query string parameters must be percent-encoded `except alphanumeric, hyphen, underscore, and period`, for example, all characters matching the RegExp `/[^0-9a-zA-Z\-_\.]/`.
* Space characters must be replaced by `%20` (NOT `+` character).
* Each key-value pair must be separated by `ampersand` character.
* Unicode characters must be broken up into `UTF-8` encoded bytes before percent-encoding.
* Final signed value should be `Base64 encoded` using the `URL safe` characters `-` and `_` replacing `+` and `/` respectively.

As a rule of constructing the `GET query params`, all query params passed to PubNub via the actual GET call must match the query params recorded in the signature body. PubNub servers perform the identical calculation to verify the `secret key` and will fail with signature mismatch due to lack of parity between the GET query params in the request and the signature body.

Additionally, a `timestamp` parameter is required to ensure NTP synchronization. The value can be generated using the following snippet in javascript:

```javascript
const timestamp = Math.floor(new Date().getTime() / 1000);
```

:::warning For NTP synchronization
please ensure that you have configured NTP on your server to keep the clock in sync. This is to prevent system clock drift leading to 400 `Invalid Timestamp` error response. [https://support.pubnub.com/hc/en-us/articles/360051973331-Why-do-I-get-Invalid-Timestamp-when-I-try-to-grant-permission-using-Access-Manager-](https://support.pubnub.com/hc/en-us/articles/360051973331-Why-do-I-get-Invalid-Timestamp-when-I-try-to-grant-permission-using-Access-Manager-)
:::

For example, we would like to sign the following request:

* `https://ps.pndsn.com/publish/demoPublishKey/demoSubscribeKey/0/my-channel/0/%22my-message%22`
* publish key: demoPublishKey
* subscribe key: demoSubscribeKey
* secret key: secretKey
* GET query params: store: 1, seqn: 1, auth: myAuth, timestamp: 1535125017, pnsdk: PubNub-Go/4.1.2, uuid: myUuid

The signature body will look like:

```javascript
demoSubscribeKey
demoPublishKey
/publish/demoPublishKey/demoSubscribeKey/0/my-channel/0/%22my-message%22
store=1&seqn=1&auth=myAuth&timestamp=1535125017&pnsdk=PubNub-Go/4.1.2&uuid=myUuid
```

The signature body is then encrypted using `HMAC + SHA256` with the `secret key` supplied by the PubNub Admin panel and passed to the server via the `signature` query param.

For the above example, the resulting signature will be: `whUwGhCika3QdlVj6LRg8XE4pNvsr4m3VX1G6u-s_wU=` and the request will look as follows:

```javascript
GET https://ps.pndsn.com/publish/demoPublishKey/demoSubscribeKey/0/my-channel/0/%22my-message%22?store=1&seqn=1&auth=myAuth&timestamp=1535125017&pnsdk=PubNub-Go/4.1.2&uuid=myUuid&signature=whUwGhCika3QdlVj6LRg8XE4pNvsr4m3VX1G6u-s_wU=
```

## Grant example

Assuming the server would like to grant the clients read access to channels `a` and `b` using auth token `key1` and the access will last for 15 minutes:

* `/v2/auth/grant/sub-key/demoSubscribeKey`
* publish key: demoPublishKey
* subscribe key: demoSubscribeKey
* secret key: secretKey
* GET query params: uuid: myUuid, auth: key1, ttl: 15, r: true, w: false, m: false, timestamp: 123456

The following signature body will be generated:

```javascript
demoSubscribeKey
demoPublishKey
/v2/auth/grant/sub-key/demoSubscribeKey
auth=key1&r=1&ttl=15&uuid=myUuid&w=0&m=0
```

Once encrypted, the following signature will be calculated:

```javascript
Cq6mq1-N0ww7nwow06gydMJogxVuBTMjEF3e8Hnv3L4=
```

And the GET request can now be performed:

```javascript
GET http://ps.pndsn.com/v2/auth/grant/sub-key/demoSubscribeKey?auth=key1&store=false&timestamp=123456&ttl=15&uuid=myUuid&signature=Cq6mq1-N0ww7nwow06gydMJogxVuBTMjEF3e8Hnv3L4=&r=1&w=0&m=0
```