On this page

Access control and limits in DataSync

DataSync is secure by default. Access Manager must be enabled on your keyset, and every request must be authorized. There is no anonymous access.

DataSync extends Access Manager. It uses the same tokens that already protect your channels, with new resource types for entities, relationships, and memberships. Refer to Access control and permissions management for how Access Manager tokens work in general. This page covers what DataSync adds on top.

Authorizing requests

Each DataSync request carries exactly one credential: an Access Manager token (for your clients) or a request signature (for your servers). Sending both is an error, and sending neither is rejected with a 401.

Over REST, the credential is a query parameter, auth for a token or signature for a signed request. Both are documented on every DataSync endpoint, for example on Get entities.

Access Manager is required

If Access Manager is not enabled on your keyset, DataSync requests fail. Enable Access Manager in Admin Portal before using DataSync.

DataSync itself is a separate keyset switch. If DataSync isn't enabled on the keyset, every request fails with a 403, whatever credential it carries. Refer to Configuration.

The typical split follows the same pattern as the rest of PubNub: your servers hold signing credentials and grant tokens, and your clients use the tokens they're granted.

Permissions and resource types

Access Manager tokens grant permissions on resources. DataSync adds three resource types:

  • datasync:entities
  • datasync:relationships
  • datasync:memberships

User and channel entities reuse the existing channels and users resource types.

DataSync user entities Access Manager grants

DataSync checks the users resource type for user entities. It does not check uuids, the resource type App Context and the general Access control examples use for granting access to a User ID's metadata.

A token that only grants uuids permissions does not authorize DataSync operations on the corresponding user entity. Grant users explicitly.

users and uuids both take a User ID, but they are separate scopes that different products read, which is why a uuids-only token fails here. A single grant request may still carry only one of them: SDKs reject a request that names both, and the check spans the whole request, so resources.users can't be paired with patterns.uuids either. authorizedUserId and authorized_uuid pair up the same way. Keep uuids only while you still grant App Context UUID metadata permissions. Refer to Grant DataSync permissions for the grant call itself.

Each DataSync object kind authorizes against a specific resource type. Generic entities, relationships, and memberships use the new datasync: types, while user and channel entities reuse the existing users and channels types, not uuids:


Every DataSync resource takes the same four CRUD permissions, and so does users:

Resource typePermissions
users
create, get, update, delete
channels
read, write, get, manage, update, join, delete
datasync:entities, datasync:relationships, datasync:memberships
create, get, update, delete

read, write, manage, and join stay messaging concepts. They aren't available on users or on any datasync: resource type. On channels they gate publishing, subscribing, and Presence, so a DataSync read of a channel entity turns on get, not read.

Grants target either exact ids or patterns (regular expressions), following the same model Access Manager already uses for channels.

In Bob's marketplace, Bob's token could grant update on product-sneaker-42 by exact ID, and get on every product, including product-sneaker-42 and product-cap-7, through a single pattern matching the product- prefix. Reading a DataSync object is get, not read. read is a channel permission, and on a DataSync object it governs only whether you can subscribe to its events.

Subscribing to events

Receiving DataSync events requires subscribe permission on every channel an event reaches, granted the same way as any other channel grant. An entity's own ID channel is always one of them for events about that entity.

A relationship or membership has no ID channel of its own, its events reach only the ID channels of the two entities it links. Refer to Events for the full routing model.

Beyond the object's own ID channel, each named projection on the class has a channel of its own, __<projection>__<id>. Subscribing to the ID channel gives you the __default__ view of the payload, and subscribing to a projection channel gives you that projection's view. A client that needs the admin view of product-sneaker-42 in real time needs subscribe permission on __admin__product-sneaker-42, not on product-sneaker-42.

This holds however the client subscribes. A DataSync SDK entity with a projection option resolves to the same channel name, so it needs the same grant.

Field-level access with projections

Beyond granting access to a resource, a token can also select which fields of that resource it can read and write. Tokens carry a pn-projections map inside their meta section, with two nested maps:

  • res for exact resource ids
  • pat for regular-expression patterns

Each is keyed by object kind plus ID (or pattern), with each value naming the projection granted for that resource. These keys use their own datasync: prefixes, which are separate from the resource types you grant permissions on above. Users and channels are granted through users and channels, but their projection keys are datasync:users: and datasync:channels::

  • datasync:users: for users
  • datasync:entities: for generic entities
  • datasync:channels: for channels
  • datasync:relationships: for relationships
  • datasync:memberships: for memberships
{
"meta": {
"pn-projections": {
"res": {
"datasync:users:user-alice": "admin"
},
"pat": {}
}
}
}

With no matching entry in res or pat, a token gets the __default__ projection. Requesting a projection name that doesn't exist on the class is rejected with a 403.

A replace is scoped to the token's projection, which is a guarantee worth designing around: a token holding a narrow projection can't wipe the fields it can't see, because fields outside the projection keep their stored values.

Projections and events

Projections scope events as well as API reads and writes. Each event is published once per projection declared on the object's class: to the object's ID channel for __default__, and to __<projection>__<id> for each named projection, with the payload on each channel limited to that projection's fields. Grant subscribe permission on the projection channel your client needs. Refer to Events and Projections for the full model.

Limits

Current service limits for DataSync:

LimitValue
Page size (limit)
1 to 100, default 20
Pagination direction
forward only
Projections per class
3, including __default__
Projection name length
64 characters
id length
255 characters
id characters
No whitespace, commas, colons, asterisks, forward slashes, backslashes, or control characters
Class name length
128 characters
status length
100 characters
Filter predicate count
10 by default, configurable per keyset
TTL (config.ttlSec)
0 to 315569260 seconds (about 10 years), default 2678400 seconds (31 days)

Error responses

Every error body uses the same envelope, and errorCode is the stable programmatic contract, not the message text. A validation failure can return more than one item:

{
"errors": [
{ "errorCode": "DS-0650", "message": "...", "path": "..." }
]
}

Every DataSync code carries the DS- prefix. path appears only on codes that can point at one input, and its form follows the code: a JSON Pointer into the request payload, a query parameter name such as filter or sort, a field name, or a class property name.

Each Core REST API endpoint lists the exact codes its own responses can return, per status. Refer to the Responses section on any endpoint, for example Create entity.

Common failure conditions and the status code DataSync returns for each:

ConditionStatus
No credential
401
An expired, revoked, malformed, or otherwise unauthorized token
403
A projection name that doesn't exist on the class
403
An object id that doesn't exist, on get, replace, partial update, or delete
404
A class, or a specific class version, that doesn't exist on create
404
A relationship or membership endpoint where a linked entity doesn't exist
404
An unknown subscribe key
404
An id that already exists on create
409
A relationship that would violate its class's cardinality
409
A stale eTag on If-Match
412
A patch that touches any path other than /status, the class version, and /payload or anything under it
400
A payload that fails a declared property's type or nullability check
400
Both filter_fast and filter on one request
400
A malformed filter, or more predicates than the limit allows
400
Sorting by a property that isn't sortable in that context, or an invalid cursor
400
Malformed JSON in the request body
400
An unsupported Content-Type
415
An Accept header DataSync can't satisfy
406
A write outside the token's resolved projection
403
Modifying the definition of a class defined at the Global level, such as User, Channel, or Membership
403
A class property named id, createdAt, or updatedAt, or a status property at any path other than /status
400
Deleting a class version that another class extends
409

The two projection-related 403s, an unknown projection name and a write outside the resolved projection, share one error code and the deliberately generic message Invalid value for 'auth' parameter. Neither response names the projection or the field involved. That's by design, so the response doesn't disclose which projections or fields exist.

In Bob's marketplace, granting user-alice get access to product-sneaker-42 and to every product- entity by pattern, scoped to the public projection, looks like this:

1const token = await pubnub.grantToken({
2 ttl: 15,
3 authorizedUserId: 'user-alice',
4 resources: {
5 dataSync: {
6 entities: {
7 'product-sneaker-42': { get: true },
8 },
9 },
10 },
11 patterns: {
12 dataSync: {
13 entities: {
14 'product-.*': { get: true },
15 },
show all 30 lines

Refer to Grant token (JavaScript) and Grant token (C#) for the full parameter reference, including how users and channels permissions cover DataSync's built-in user and channel entities.