tsndr / cloudflare-worker-jwt

A lightweight JWT implementation with ZERO dependencies for Cloudflare Workers.
MIT License
649 stars 51 forks source link

Signing/Verifying an ES256 JWT fails #64

Closed dtarnawsky closed 7 months ago

dtarnawsky commented 7 months ago

Using jwt.sign to create a JWT to post to Apple's Device Check API (docs) is resulting in an error "Missing or badly formatted authorization token". Apple's API requires an ES256 algorithm, private key and kid in the header.

I think there may a problem when signing with this algorithm so I wrote a unit test to sign and then verify the signed token which fails with an error InvalidAccessError: Unable to use this key to verify.

Here's the unit test to use:

import { describe, expect, test } from '@jest/globals'
import jwt from '../src/index'

describe('Test ES256 Sign and Verify', () => {
    test('ES256 Sign and Verify', async () => {        
        const secret = '-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----';
        const token = await jwt.sign({
            iss: '123456789',
            iat: Math.floor(Date.now() / 1000) - (1 * 360),
            exp: Math.floor(Date.now() / 1000) + (24 * (60 * 60))
        }, secret, { algorithm: 'ES256', header: { kid: '987654321', type: 'JWT' } });

        const verified = await jwt.verify(token, secret, { algorithm: 'ES256', throwError: true })
        expect(verified).toBeTruthy()

    })
})

Perhaps I've written a bad unit test or Apple just doesn't like my token, but I figured it would be worth posting here to see if it looks like a real issue as I would think calling sign to get a token and then verifying it would result in a verified token.

dtarnawsky commented 7 months ago

For anyone looking at this issue I found the answer using jose, the secret needs to be imported using importPKCS8.

There is likely an equivalent way with cloudflare-worker-jwt.

zer0stars commented 6 months ago

Having the same issue, do you have an example?

dtarnawsky commented 6 months ago

Hey @zer0stars , if you are using the Device Check api from Apple then Apple will return this error when you are testing your app via XCode, if you deploy to Test Flight then it works - there is nothing wrong with the JWT and "Missing or badly formatted authorization token" really means that Apple will not accept it as it is coming from a device it does not trust. I ended up writing about this in this tutorial.