Skip to content

Commit

Permalink
feat(open-payments): generateJwk (#788)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurapov authored Nov 28, 2022
1 parent d386d4e commit 48cdfa2
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/open-payments/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export {
AuthenticatedClient,
UnauthenticatedClient
} from './client'

export { generateJwk } from './jwk'
44 changes: 44 additions & 0 deletions packages/open-payments/src/jwk.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { generateKeyPairSync } from 'crypto'
import { generateJwk } from './jwk'

describe('jwk', (): void => {
describe('generateJwk', (): void => {
test('properly generates jwk', async (): Promise<void> => {
expect(generateJwk({ keyId: 'keyid' })).toEqual({
alg: 'EdDSA',
kid: 'keyid',
kty: 'OKP',
crv: 'Ed25519',
x: expect.any(String)
})
})

test('properly generates jwk with defined private key', async (): Promise<void> => {
expect(
generateJwk({
keyId: 'keyid',
privateKey: generateKeyPairSync('ed25519').privateKey
})
).toEqual({
alg: 'EdDSA',
kid: 'keyid',
kty: 'OKP',
crv: 'Ed25519',
x: expect.any(String)
})
})

test('throws if empty keyId', async (): Promise<void> => {
expect(() => generateJwk({ keyId: '' })).toThrow('KeyId cannot be empty')
})

test('throws if provided key is not EdDSA-Ed25519', async (): Promise<void> => {
expect(() =>
generateJwk({
keyId: 'keyid',
privateKey: generateKeyPairSync('ed448').privateKey
})
).toThrow('Key is not EdDSA-Ed25519')
})
})
})
34 changes: 34 additions & 0 deletions packages/open-payments/src/jwk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createPublicKey, generateKeyPairSync, KeyObject } from 'crypto'
import { JWK } from './types'

export const generateJwk = ({
privateKey: providedPrivateKey,
keyId
}: {
privateKey?: KeyObject
keyId: string
}): JWK => {
if (!keyId.trim()) {
throw new Error('KeyId cannot be empty')
}

const privateKey = providedPrivateKey
? providedPrivateKey
: generateKeyPairSync('ed25519').privateKey

const jwk = createPublicKey(privateKey).export({
format: 'jwk'
})

if (jwk.crv !== 'Ed25519' || jwk.kty !== 'OKP') {
throw new Error('Key is not EdDSA-Ed25519')
}

return {
alg: 'EdDSA',
kid: keyId,
kty: jwk.kty,
crv: jwk.crv,
x: jwk.x
}
}

0 comments on commit 48cdfa2

Please sign in to comment.