Push Notification Security: Separate Tokens from Permission

Secure push publishing with scoped sender access, recipient authorization, token lifecycle controls and a release check that prevents accidental mass sends.

In this article

A push registration token identifies a delivery target; it is not a complete authorization policy. A secure notification service separately decides who may send, which recipients they may reach and which message types are allowed. Keep sender credentials out of client applications and protect mass-send workflows with explicit controls.

This guide addresses the publishing path rather than device notification design. It is useful for startups that add mobile or browser notifications and then discover that a single backend action can contact their entire user base.

Separate the three identities

Distinguish the authenticated user, the installation or browser subscription and the backend sender. One user may own multiple installations. A shared device may change users. The sender may be a scheduled job, administrator or application service.

Store the relationship between a delivery target and the account that authorized it. Update that relationship during logout, account change and token refresh according to your product's design. Do not let the client choose an arbitrary account ID and attach its token without server-side ownership checks.

Firebase's registration-token management guidance discusses token lifecycle. Treat those lifecycle controls as one part of delivery correctness, alongside your own authorization and recipient selection.

Create a narrow publishing operation

Define message types with fixed purposes, such as order updates or approved editorial announcements. Decide which service identity may publish each type. Restrict the destination scope: one account, a verified segment or a controlled global audience.

json
{"message_type":"order-update","account_id":"fixture-42",
 "order_id":"fixture-300","template_version":"v2",
 "audience_scope":"single-account"}

This fixture is a request to your own backend, not a provider API example. The backend should derive authorized recipients rather than trusting a client-supplied list of unrelated account IDs. Inspect sanitized requests with JSON Viewer.

Avoid a general endpoint that accepts arbitrary text, arbitrary destination tokens and a broad sender credential. It may be convenient for testing but creates a powerful action that needs a carefully enforced access boundary.

Keep credentials on the sender side

Never ship privileged sender keys in a mobile bundle, public repository or browser script. Client code is inspectable. Environment-variable names beginning with a public prefix do not create a secret storage boundary.

Use the provider's supported server authentication and limit who can retrieve or use it. Keep development and production senders separate. A local test should not accidentally reuse a production audience because both environments read the same credential and token table.

Record credential rotation and owner responsibility without placing credentials in logs. If a sender credential is exposed, follow the provider's revocation procedure and investigate use during the exposure period. Merely hiding the value in the interface does not invalidate a copied key.

Validate the message and its destination

Use approved templates for sensitive workflows. Check lengths, permitted fields and allowed deep-link destinations. A notification title may be harmless while the linked destination leads outside the expected application.

Do not include confidential details in lock-screen previews by default. Think about what another person holding the device could see. A generic alert can invite the user into the authenticated application for the full content.

Review localization too. A message approved in one language should not acquire an unrelated call to action during translation. Keep templates and their versions in reviewable records, using Text Diff for sanitized copy changes.

Handle token churn and delivery errors

Expect tokens or subscriptions to change. Keep an updated timestamp and process provider errors according to current documentation. Remove invalid targets using a deliberate cleanup policy; do not retry permanent failures forever.

Track the difference between provider acceptance and user-visible delivery. Acceptance does not mean every device displayed the notification. Offline devices, operating-system policy and user preferences can affect the final outcome.

Also prevent duplicate sends from a retrying job. Keep a publication record that identifies the message, recipient scope and outcome. Reconcile a timed-out provider request before blindly repeating a large broadcast. The deduplication strategy belongs in the delivery design, not in an operator's memory.

Test the failure that matters most

Use dedicated test installations and synthetic accounts. Confirm that an ordinary user cannot trigger a global send, that one tenant cannot target another and that a development sender cannot reach production recipients.

Exercise a stale token, a logged-out installation and a changed account association. Verify the backend refuses unauthorized deep links and recipient scopes. Use a dry-run audience count before large editorial sends, with a reviewed upper bound appropriate to the operation.

Publish with a visible audit trail

Record who initiated the send, which template was used, how the audience was derived and what the provider reported. Keep raw tokens restricted; broad analytics dashboards usually need counts and internal identifiers, not delivery secrets.

Make authorization precede delivery

Tokens help route messages. Permission controls decide whether the message should be sent. Separate those responsibilities, protect server credentials and test recipient boundaries before enabling a broadcast workflow.

Advertisement