@sphereon/oid4vci-client
Version:
OpenID for Verifiable Credential Issuance (OpenID4VCI) client
105 lines (91 loc) • 3.49 kB
text/typescript
import { Alg, Jwt } from '@sphereon/oid4vci-common';
import { CredentialMapper } from '@sphereon/ssi-types';
import { fetch } from 'cross-fetch';
import { importJWK, JWK, SignJWT } from 'jose';
import { OpenID4VCIClientV1_0_11 } from '..';
export const UNIT_TEST_TIMEOUT = 30000;
const ISSUER_URL = 'https://launchpad.vii.electron.mattrlabs.io';
const jwk: JWK = {
crv: 'Ed25519',
d: 'kTRm0aONHYwNPA-w_DtjMHUIWjE3K70qgCIhWojZ0eU',
x: 'NeA0d8sp86xRh3DczU4m5wPNIbl0HCSwOBcMN3sNmdk',
kty: 'OKP',
};
// pub hex: 35e03477cb29f3ac518770dccd4e26e703cd21b9741c24b038170c377b0d99d9
// priv hex: 913466d1a38d1d8c0d3c0fb0fc3b633075085a31372bbd2a8022215a88d9d1e5
const did = `did:key:z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
const kid = `${did}#z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
describe.skip('OID4VCI-Client using Mattr issuer should', () => {
async function test(format: 'ldp_vc' | 'jwt_vc_json') {
const offer = await getCredentialOffer(format);
const client = await OpenID4VCIClientV1_0_11.fromURI({
uri: offer.offerUrl,
kid,
alg: Alg.EdDSA,
});
expect(client.credentialOffer).toBeDefined();
expect(client.endpointMetadata).toBeDefined();
expect(client.getCredentialEndpoint()).toEqual(`${ISSUER_URL}/oidc/v1/auth/credential`);
expect(client.getAccessTokenEndpoint()).toEqual('https://launchpad.vii.electron.mattrlabs.io/oidc/v1/auth/token');
const accessToken = await client.acquireAccessToken();
// console.log(accessToken);
expect(accessToken).toMatchObject({
expires_in: 3600,
scope: 'OpenBadgeCredential',
token_type: 'Bearer',
});
const credentialResponse = await client.acquireCredentials({
credentialTypes: 'OpenBadgeCredential',
format,
proofCallbacks: {
signCallback: proofOfPossessionCallbackFunction,
},
});
expect(credentialResponse.credential).toBeDefined();
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credentialResponse.credential!);
expect(format.startsWith(wrappedVC.format)).toEqual(true);
}
it(
'succeed in a full flow with the client using OpenID4VCI version 11 and ldp_vc',
async () => {
await test('ldp_vc');
},
UNIT_TEST_TIMEOUT,
);
it(
'succeed in a full flow with the client using OpenID4VCI version 11 and jwt_vc_json',
async () => {
await test('jwt_vc_json');
},
UNIT_TEST_TIMEOUT,
);
});
interface CreateCredentialOfferResponse {
id: string;
offerUrl: string;
}
async function getCredentialOffer(format: 'ldp_vc' | 'jwt_vc_json'): Promise<CreateCredentialOfferResponse> {
const credentialOffer = await fetch('https://launchpad.mattrlabs.com/api/credential-offer', {
method: 'post',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
//make sure to serialize your JSON body
body: JSON.stringify({
format,
type: 'OpenBadgeCredential',
userId: '622a9f65-21c0-4c0b-9a6a-f7574c2a1549',
userAuthenticationRequired: false,
}),
});
return (await credentialOffer.json()) as CreateCredentialOfferResponse;
}
async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
const importedJwk = await importJWK(jwk, 'EdDSA');
return await new SignJWT({ ...args.payload })
.setProtectedHeader({ ...args.header })
.setIssuedAt()
.setExpirationTime('2h')
.sign(importedJwk);
}