Commit 8de542ab authored by Hidde-Jan Jongsma's avatar Hidde-Jan Jongsma

Add decoding request jwts

parent e013aaec
import uuidv4 from 'uuid/v4';
interface CredentialData {
[key: string]: string | number | boolean | null;
}
export interface CredentialIssueRequestData {
iss: string;
type: string;
data: CredentialData;
callbackUrl: string; // the REST api of the verifier where to deliver the credential data
}
export class CredentialIssueRequest {
requestId: string;
constructor(
protected issuerId: string,
public credentialType: string,
public credentialData: CredentialData,
public callbackUrl: string,
) {
this.requestId = `credential-issue-request-${uuidv4()}`;
}
}
import uuidv4 from 'uuid/v4';
export interface CredentialVerifyRequestData {
iss: string;
type: string;
callbackUrl: string; // the REST api of the verifier where to deliver the credential data
}
export class CredentialVerifyRequest {
requestId: string;
constructor(
protected verifierId: string,
public credentialType: string,
public callbackUrl: string,
) {
this.requestId = `credential-verify-request-${uuidv4()}`;
}
}
import { Module } from '@nestjs/common';
import { RequestsService } from './requests.service';
import { OrganizationsModule } from '../organizations/organizations.module';
@Module({})
@Module({
imports: [OrganizationsModule],
providers: [RequestsService],
exports: [RequestsService],
})
export class RequestsModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { RequestsService } from './requests.service';
describe('RequestsService', () => {
let service: RequestsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [RequestsService],
}).compile();
service = module.get<RequestsService>(RequestsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable } from '@nestjs/common';
import { decode, verify } from 'jsonwebtoken';
import { OrganizationsService } from 'src/organizations/organizations.service';
import { Organization } from 'src/organizations/organization.entity';
import {
CredentialVerifyRequest,
CredentialVerifyRequestData,
} from './credential-verify-request';
import {
CredentialIssueRequest,
CredentialIssueRequestData,
} from './credential-issue-request';
export class InvalidRequestJWT extends Error {}
const JWT_MAX_AGE = '300s';
@Injectable()
export class RequestsService {
constructor(private organizationsService: OrganizationsService) {}
async decodeVerifyRequestToken(jwt: string) {
const { request, requestor } = await this.decodeAndVerifyJwt<
CredentialVerifyRequestData
>(jwt);
return {
verifyRequest: new CredentialVerifyRequest(
request.iss,
request.type,
request.callbackUrl,
),
verifier: requestor,
};
}
async decodeIssueRequestToken(jwt: string) {
const { request, requestor } = await this.decodeAndVerifyJwt<
CredentialIssueRequestData
>(jwt);
return {
issueRequest: new CredentialIssueRequest(
request.iss,
request.type,
request.data,
request.callbackUrl,
),
issuer: requestor,
};
}
async decodeAndVerifyJwt<T>(
jwt: string,
): Promise<{ request: T; requestor: Organization }> {
try {
// First decode to extract issuer
const decoded = decode(jwt, { json: true });
// Check if issuer is set
if (!decoded || !decoded.iss) {
throw new Error('Could not decode issuer');
}
const requestor = await this.organizationsService.findByIdentifier(
decoded.iss,
);
if (!requestor) {
throw new Error('Could not find requestor');
}
// Verify that jwt is signed by specified issuer
const request = verify(jwt, requestor.sharedSecret, {
maxAge: JWT_MAX_AGE,
});
if (typeof request === 'string') {
throw new Error(`String returned '${request}'. Expecting json object`);
}
return { request, requestor };
} catch (e) {
throw new InvalidRequestJWT('Could not decode request JWT');
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment