-1.8 C
New York
Thursday, February 20, 2025

ios – Apple server notifications JWT Invalid Header


I’m utilizing the next code to implement apple server notifications, nevertheless it’s giving me an error “Invalid JWT Header”. I’m utilizing storekit2 to buy subscriptions within the app and I am utilizing a node js backend to maintain observe of subscription updates. Can somebody assist?

Once I debug additional I get JWT verification failed: Error: Invalid JWT header: Lacking child

I believe the difficulty is that apple has not enabled V2 and continues to be sending V1 payload as a result of I do not see signedPayload within the response from apple. How can I get it to ship V2?

const APPLE_JWKS_URL = "https://appleid.apple.com/auth/keys";
const getApplePublicKey = async (child) => {
    strive {
        const response = await axios.get(APPLE_JWKS_URL);
        const keys = response.information.keys;
        const key = keys.discover((ok) => ok.child === child);

        if (!key) {
            throw new Error("Matching key not discovered");
        }

        return jwksClient.certToPEM({
            kty: key.kty,
            n: key.n,
            e: key.e,
        });
    } catch (error) {
        console.error("Didn't fetch Apple's public key:", error);
        throw new Error("Couldn't get Apple public key");
    }
};

// Perform to confirm Apple's JWT signature
const verifyAppleJWT = async (token) => {
    strive {
        const decodedHeader = jwt.decode(token, { full: true });

        if (!decodedHeader || !decodedHeader.header.child) {
            throw new Error("Invalid JWT header");
        }

        const publicKey = await getApplePublicKey(decodedHeader.header.child);
        return jwt.confirm(token, publicKey, { algorithms: ["RS256"] });
    } catch (error) {
        console.error("JWT verification failed:", error);
        return null;
    }
};

// Apple Server Notification Endpoint
router.publish("/apple-server-notifications", async (req, res) => {
    strive {
        const { signedPayload } = req.physique;

        if (!signedPayload) {
            return res.standing(400).json({ error: "Lacking signedPayload" });
        }

        // Confirm the JWT signature with Apple's public key
        const payload = await verifyAppleJWT(signedPayload);
        if (!payload) {
            return res.standing(400).json({ error: "Invalid notification" });
        }

        console.log("Verified Notification:", JSON.stringify(payload, null, 2));

        // Extract related information
        const eventType = payload.notificationType;
        const originalTransactionId = payload.information.originalTransactionId;

        // Deal with subscription occasions
        change (eventType) {
            case "SUBSCRIBED":
            case "DID_RENEW":
                await updateSubscription(originalTransactionId, "lively");
                break;
            case "EXPIRED":
                await updateSubscription(originalTransactionId, "expired");
                break;
            case "CANCEL":
                await updateSubscription(originalTransactionId, "canceled");
                break;
            case "DID_REVOKE":
                await updateSubscription(originalTransactionId, "revoked");
                break;
            default:
                console.log(`Unhandled occasion kind: ${eventType}`);
        }
        res.standing(200).json({ message: "Notification processed" });
    } catch (error) {
        console.error("Error dealing with notification:", error);
        res.standing(500).json({ error: "Inside Server Error" });
    }
});

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles