https://github.com/seventwo-studio/expo-passkite
Expo module for generating Apple Wallet and Google Wallet passes from React Native
https://github.com/seventwo-studio/expo-passkite
apple-wallet expo expo-module google-wallet passkit pkpass react-native typescript wallet
Last synced: 9 days ago
JSON representation
Expo module for generating Apple Wallet and Google Wallet passes from React Native
- Host: GitHub
- URL: https://github.com/seventwo-studio/expo-passkite
- Owner: seventwo-studio
- License: mit
- Created: 2025-04-06T20:12:58.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-05-25T01:01:01.000Z (15 days ago)
- Last Synced: 2026-05-25T02:34:40.239Z (15 days ago)
- Topics: apple-wallet, expo, expo-module, google-wallet, passkit, pkpass, react-native, typescript, wallet
- Language: TypeScript
- Homepage: https://seventwo-studio.github.io/expo-passkite/
- Size: 1.17 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# expo-passkite
Generate Apple Wallet passes (`.pkpass`), add them to iOS Wallet, and save Google Wallet JWTs on Android.
**[Documentation](https://seventwo-studio.github.io/expo-passkite/)** | **[API Reference](https://seventwo-studio.github.io/expo-passkite/reference/api/)** | **[Setup Guide](https://seventwo-studio.github.io/expo-passkite/guides/setup-credentials/)**
## Installation
```bash
npx expo install expo-passkite
```
## Configuration
Add the config plugin to your `app.json` or `app.config.js`:
```json
{
"expo": {
"plugins": [
["expo-passkite", {
"passTypeIdentifiers": ["$(TeamIdentifierPrefix)pass.com.example.myapp"]
}]
]
}
}
```
Then run prebuild:
```bash
npx expo prebuild
```
## Usage
The package ships two entry points so React Native bundles never pull in Node-only signing code:
| Entry point | Use it for | Runs in |
| --- | --- | --- |
| `expo-passkite` | Adding passes to Apple Wallet, querying state, listening to events, types/enums | React Native, web |
| `expo-passkite/server` | Building, signing, and packaging `.pkpass` files (`Pass`, `PassBuilder`, credential helpers, certificates) | Node, Bun, your backend |
The server entry depends on `node-forge`, `jszip`, and `node:fs`. Importing it from a React Native runtime will fail — generate passes on a server and ship the resulting `.pkpass` (or its base64 form) to the device.
### Creating a Pass (server)
```typescript
import {
createPassBuilder,
createPass,
PassType,
BarcodeFormat,
PassImageType,
} from 'expo-passkite/server';
// Build pass data
const builder = createPassBuilder()
.setIdentifiers({
passTypeIdentifier: 'pass.com.example.myapp',
serialNumber: 'E5982H-I2',
teamIdentifier: 'A93A5CM278',
})
.setOrganization({
organizationName: 'Example Inc.',
description: 'Example Store Card',
logoText: 'Example',
})
.setPassType(PassType.StoreCard)
.setColors({
backgroundColor: 'rgb(206, 140, 53)',
foregroundColor: 'rgb(255, 255, 255)',
})
.addPrimaryField({
key: 'balance',
label: 'Balance',
value: '$50.00',
})
.addBarcode({
format: BarcodeFormat.QR,
message: 'https://example.com/card/E5982H-I2',
altText: 'E5982H-I2',
});
const { passData, images } = builder.build();
// Create the pass
const pass = createPass(passData, images);
// Set signing credentials (required for valid passes)
pass.setSigningCredentials({
wwdrCertificate: wwdrCertPem,
signerCertificate: signerCertPem,
signerKey: signerKeyPem,
signerKeyPassphrase: 'password', // if key is encrypted
});
// Generate .pkpass file
const pkpassBuffer = await pass.generate();
// Or generate as base64 for sending to native module
const pkpassBase64 = await pass.generateBase64();
```
### Adding to Wallet
```typescript
import {
addPassToWallet,
canAddPasses,
isPassLibraryAvailable,
containsPass,
} from 'expo-passkite';
// Check if wallet is available
const available = await isPassLibraryAvailable();
const canAdd = await canAddPasses();
if (canAdd) {
// Generate pass as base64
const passBase64 = await pass.generateBase64();
// Add to Apple Wallet on iOS
const result = await addPassToWallet(passBase64);
if (result.success) {
console.log('Pass added successfully!');
} else {
console.error('Failed to add pass:', result.error);
}
}
// Check if a specific pass exists
const exists = await containsPass('pass.com.example.myapp', 'E5982H-I2');
```
### Listening to Events
```typescript
import { onPassAdded, onPassRemoved } from 'expo-passkite';
// Subscribe to pass added events
const addedSubscription = onPassAdded((event) => {
console.log('Pass added:', event.passTypeIdentifier, event.serialNumber);
});
// Subscribe to pass removed events
const removedSubscription = onPassRemoved((event) => {
console.log('Pass removed:', event.passTypeIdentifier, event.serialNumber);
});
// Clean up
addedSubscription.remove();
removedSubscription.remove();
```
## Pass Types
- `PassType.BoardingPass` - Airline, train, bus, boat boarding passes
- `PassType.Coupon` - Coupons and offers
- `PassType.EventTicket` - Concert, movie, sports event tickets
- `PassType.StoreCard` - Loyalty and membership cards
- `PassType.Generic` - General purpose passes
## Signing Passes
To create valid passes that can be added to Apple Wallet, you need:
1. **Apple Developer Account** with Pass Type ID capability
2. **Pass Type ID** registered in Apple Developer Portal
3. **Pass Type ID Certificate** (.p12 or .pem)
4. **Apple WWDR Certificate** (Worldwide Developer Relations)
### Obtaining Certificates
1. Log in to [Apple Developer Portal](https://developer.apple.com)
2. Go to Certificates, Identifiers & Profiles
3. Create a Pass Type ID under Identifiers
4. Create a Pass Type ID Certificate under Certificates
5. Download the WWDR certificate from Apple
### Converting Certificates
```bash
# Convert .p12 to PEM files
openssl pkcs12 -in pass.p12 -out signerCert.pem -clcerts -nokeys
openssl pkcs12 -in pass.p12 -out signerKey.pem -nocerts -nodes
```
## Android / Google Wallet
Android cannot add Apple `.pkpass` files directly. Use an explicit Google Wallet JWT API instead:
1. Set up a Google Wallet API account
2. Create pass classes and objects via the Google Wallet API
3. Generate a signed JWT token server-side
4. Pass the JWT to `addGoogleWalletJwt(jwt)` or `addPassToWallet({ type: 'google-wallet', jwt })`
```typescript
import { addGoogleWalletJwt, addPassToWallet } from 'expo-passkite';
const jwt = await fetchGoogleWalletJwt(userId);
await addGoogleWalletJwt(jwt);
// Or use the discriminated wallet payload:
await addPassToWallet({ type: 'google-wallet', jwt });
```
See [Google Wallet API documentation](https://developers.google.com/wallet) for details.
## Documentation
For complete documentation, visit **[seventwo-studio.github.io/expo-passkite](https://seventwo-studio.github.io/expo-passkite/)**
- [Getting Started](https://seventwo-studio.github.io/expo-passkite/getting-started/introduction/)
- [Setup Credentials](https://seventwo-studio.github.io/expo-passkite/guides/setup-credentials/)
- [Creating Passes](https://seventwo-studio.github.io/expo-passkite/guides/creating-passes/)
- [Pass Types](https://seventwo-studio.github.io/expo-passkite/guides/pass-types/)
- [Wallet Integration](https://seventwo-studio.github.io/expo-passkite/guides/wallet-integration/)
- [API Reference](https://seventwo-studio.github.io/expo-passkite/reference/api/)
- [TypeScript Types](https://seventwo-studio.github.io/expo-passkite/reference/types/)
## License
MIT