Apple Push Notification service (APNs) for Node.js - Maintained fork with security updates and TypeScript support
npm install @hrefcl/apnApple Push Notification service (APNs) for Node.js - Maintained fork with security updates and TypeScript support.



The original apn package has been unmaintained since 2019 and contains 32 security vulnerabilities in its dependencies. This fork:
- Updates all dependencies to secure versions
- Rewrites the codebase in TypeScript with full type definitions
- Uses native Node.js http2 module (no deprecated packages)
- Maintains API compatibility where possible
- Adds support for modern APNs features (VoIP, Live Activities, MDM, Safari, etc.)
``bash`
npm install @hrefcl/apnor
yarn add @hrefcl/apn
- Node.js >= 16.0.0
- Apple Developer account with push notification capabilities
- APNs authentication key (.p8 file)
`typescript
import { Provider, Notification } from '@hrefcl/apn';
// Create provider with token-based authentication
const provider = new Provider({
token: {
key: '/path/to/AuthKey_XXXXXXXXXX.p8',
keyId: 'XXXXXXXXXX',
teamId: 'YYYYYYYYYY'
},
production: false // Use true for production
});
// Create notification
const notification = new Notification({
alert: {
title: 'New Message',
body: 'Hello from APNs!'
},
badge: 1,
sound: 'default',
topic: 'com.example.myapp'
});
// Send to device(s)
const result = await provider.send(notification, [
'device-token-1',
'device-token-2'
]);
console.log(Sent: ${result.sent.length});Failed: ${result.failed.length}
console.log();
// Handle failures
for (const failure of result.failed) {
console.log(Device: ${failure.device});Reason: ${failure.response?.reason}
console.log();
}
// Shutdown when done
provider.shutdown();
`
`typescript`
const provider = new Provider(options);
#### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| token | Object | required | Token authentication options |token.key
| | string/Buffer | required | Path to .p8 file or key content |token.keyId
| | string | required | Key ID from Apple Developer |token.teamId
| | string | required | Team ID from Apple Developer |production
| | boolean | false | Use production environment |host
| | string | auto | Custom APNs host |port
| | number | 443 | Connection port |requestTimeout
| | number | 5000 | Request timeout (ms) |
#### Methods
- send(notification, recipients) - Send notification to device(s)shutdown()
- - Close all connections
`typescript`
const notification = new Notification(options);
Supported pushType values: alert, background, voip, complication, fileprovider, mdm, liveactivity, location, pushtotalk.
#### Options
| Option | Type | Description |
|--------|------|-------------|
| alert | string/Object | Alert content |badge
| | number | Badge number |sound
| | string | Sound filename |contentAvailable
| | boolean | Background fetch flag |mutableContent
| | boolean | Service extension flag |category
| | string | Action category |threadId
| | string | Thread identifier |targetContentId
| | string | Target content identifier |interruptionLevel
| | string | Focus interruption level |relevanceScore
| | number | Relevance score (0.0 to 1.0) |filterCriteria
| | string | Notification filter criteria |staleDate
| | number | Live Activity stale date |contentState
| | Object | Live Activity content state |timestamp
| | number | Live Activity timestamp |event
| | string | Live Activity event (start/update/end) |dismissalDate
| | number | Live Activity dismissal date |topic
| | string | Bundle ID |expiry
| | number/Date | Expiration time |priority
| | number | Priority (1-10) |collapseId
| | string | Collapse identifier |pushType
| | string | Push type |payload
| | Object | Custom data |id
| | string | apns-id header (UUID) |urlArgs
| | string[] | Safari push URL arguments |mdm
| | string | MDM magic string |
`typescript`
interface SendResult {
sent: Array<{ device: string }>;
failed: Array<{
device: string;
status?: string;
response?: { reason: string };
error?: Error;
}>;
}
`typescript
const result = await provider.send(notification, tokens);
for (const failure of result.failed) {
switch (failure.response?.reason) {
case 'BadDeviceToken':
// Invalid token format
break;
case 'Unregistered':
// Token no longer valid - remove from database
await removeToken(failure.device);
break;
case 'PayloadTooLarge':
// Payload exceeds 4KB
break;
case 'TooManyRequests':
// Rate limited - implement backoff
break;
default:
console.error(Unknown error: ${failure.response?.reason});`
}
}
`typescript`
const notification = new Notification({
contentAvailable: true,
topic: 'com.example.app',
pushType: 'background',
payload: {
action: 'sync-data'
}
});
`typescript`
const notification = new Notification({
alert: {
title: 'Photo from John',
subtitle: 'Vacation 2024',
body: 'Check out this amazing sunset!'
},
mutableContent: true, // Enable service extension
category: 'PHOTO',
payload: {
imageUrl: 'https://example.com/photo.jpg'
}
});
`typescript`
const notification = new Notification({
pushType: 'voip',
topic: 'com.example.app', // auto-appends .voip
payload: {
callerId: 'user-123',
callerName: 'Jane Doe'
}
});
`typescript`
const notification = new Notification({
pushType: 'liveactivity',
topic: 'com.example.app', // auto-appends .push-type.liveactivity
contentState: { score: '2-1' },
event: 'update',
timestamp: Date.now()
});
`typescript`
const notification = new Notification({
urlArgs: ['inbox', 'message-123'],
payload: { action: 'open' }
});
`typescript`
const notification = new Notification({
mdm: 'a1b2c3d4e5f6'
});
`typescript`
const notification = new Notification({
id: '6c7f28b1-2a0d-4c72-b1c4-2d5f0d6b8a64',
alert: 'Hello'
});
This package is largely API-compatible with the original apn package:
`typescript
// Before (apn)
const apn = require('apn');
const provider = new apn.Provider(options);
// After (@hrefcl/apn)
import { Provider } from '@hrefcl/apn';
const provider = new Provider(options);
`
1. Node.js 16+ required - Older versions not supported
2. Token authentication only - Certificate auth removed
3. No proxy support - May be added in future versions
This package fixes all 32 security vulnerabilities present in the original apn` package:
- CVE-2022-23529 (jsonwebtoken)
- CVE-2022-23540 (jsonwebtoken)
- CVE-2022-24772 (node-forge)
- CVE-2022-24771 (node-forge)
- CVE-2020-7720 (node-forge)
- And 27 more...
MIT - See LICENSE for details.
- Original authors: Andrew Naylor, Florian Reinhart
- Maintained by: Href SpA