Authentication
How authentication works in Juice Machine for both inbound webhooks from Apple and outbound webhooks to your destinations.
Inbound Authentication
Inbound webhooks from Apple are authenticated using a unique token in the URL path:
POST https://juicemachine.net/hooks/{inbound_token}
Token Generation
When you create an app in Juice Machine, a unique, cryptographically secure token is generated. This token:
- Is 32 characters long
- Contains only URL-safe characters
- Is unique to each app
- Can be regenerated if compromised
Token Security
Important: Treat your webhook URL like a password. Anyone with the URL can send webhooks to your Juice Machine app.
Regenerating Tokens
If you believe your token has been compromised:
- Go to your app's settings in Juice Machine
- Click Regenerate Token
- Update the webhook URL in App Store Connect
The old token is immediately invalidated and will reject any requests.
Apple Signature Verification
App Store Server Notifications V2 (subscription, IAP, and refund events) arrive as a JWS (JSON Web Signature) token signed by Apple. Juice Machine verifies every notification before accepting it:
- Juice Machine receives the notification and extracts the
signedPayloadJWS token - Validates the certificate chain in the token header against Apple's Root CA G3 certificate, including Apple's marker extensions that identify a genuine App Store Server Notifications signing certificate
- Verifies the ES256 signature with the leaf certificate's public key
- Checks the notification's
signedDateis no more than 7 days old (covers Apple's 72-hour retry schedule while rejecting stale replays) - Checks the payload's bundle ID matches your app
- Rejects the request with
401if any step fails
Notifications are also deduplicated by Apple's notificationUUID: when Apple retries
a notification Juice Machine has already accepted, the retry is acknowledged without creating
a second event or sending duplicate messages.
The embedded signedTransactionInfo and signedRenewalInfo tokens are
verified the same way before their contents are used to enrich notifications.
App Store Connect webhooks (app review, build, and TestFlight events) are plain JSON and carry no Apple signature that Juice Machine can verify. They are authenticated by your app's unique, secret webhook URL — which is why you should treat that URL like a password and regenerate it if it leaks. Payloads that don't match the App Store Connect webhook structure are rejected.
Outbound Authentication
When Juice Machine sends webhooks to your destinations, you can verify the request came from Juice Machine using these methods:
Custom Headers
Every outbound request includes identifying headers:
X-JuiceMachine-Event: DID_RENEW
X-JuiceMachine-Schema-Version: 1
User-Agent: JuiceMachine/1.0 (+https://juicemachine.net)
X-JuiceMachine-Event carries the Apple event type so you can route without parsing
the body; X-JuiceMachine-Schema-Version identifies the JSON payload schema (see the
API reference).
Webhook Signatures
Custom webhook destinations are signed so you can verify each delivery really came from Juice Machine. When you create a custom webhook destination, Juice Machine generates a signing secret for it — you'll find it on the destination's page in the dashboard. Every delivery then includes:
X-JuiceMachine-Signature: sha256=<hex digest>
The digest is an HMAC-SHA256 of the exact raw request body, keyed with your destination's signing secret. To verify, compute the same HMAC over the raw body you received and compare it to the header using a constant-time comparison:
require "openssl"
def verified?(raw_body, signature_header, signing_secret)
expected = "sha256=" + OpenSSL::HMAC.hexdigest("SHA256", signing_secret, raw_body)
return false unless expected.bytesize == signature_header.to_s.bytesize
OpenSSL.secure_compare(expected, signature_header)
end
Compute the HMAC over the body bytes exactly as received — don't parse and re-serialize the JSON first, as key ordering or whitespace differences will change the digest. Destinations created before signatures shipped don't have a signing secret and are delivered without the header; recreate the destination if you want a signed one.
IP Allowlisting
If your destination supports IP allowlisting, Juice Machine sends requests from a fixed set of IP addresses. Contact support for the current list.
Custom Authentication
For custom HTTP destinations, you can also include authentication in your destination URL:
https://api.example.com/webhooks?token=your_secret_token
The URL is stored as-is and included on every delivery, so a query-string token works with receivers that can't verify HMAC signatures. Prefer the signature verification above when you can.
User Authentication
Juice Machine uses secure session-based authentication for the dashboard:
- Passwords are hashed using bcrypt
- Sessions are stored in signed, encrypted cookies
- Rate limiting prevents brute force attacks
- All traffic is encrypted with TLS
Password Requirements
- Minimum 8 characters
- Stored using bcrypt with salt
Session Security
- Sessions last until you sign out or close your browser; "remember me" sessions expire after 2 weeks
- Sessions are invalidated on password change
- Concurrent sessions are allowed