lbx-jwt
Version:
Provides JWT authentication for loopback applications. Includes storing roles inside tokens and handling refreshing. Built-in reuse detection.
161 lines • 7.63 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseBiometricCredentialsService = void 0;
const rest_1 = require("@loopback/rest");
const webauthn_utilities_1 = require("../encapsulation/webauthn.utilities");
/**
* The base service for handling biometric credentials.
*/
class BaseBiometricCredentialsService {
constructor() {
/**
* Error message to throw when no registration was found with the provided challenge for verifying the registration response.
*/
// eslint-disable-next-line stylistic/max-len
this.NO_REGISTRATION_WITH_PROVIDED_CHALLENGE_FOUND_ERROR_MESSAGE = 'No registration with provided challenge found.';
}
// eslint-disable-next-line jsdoc/require-returns
/**
* The complete origin of your frontend.
* By default this returns https://${this.RP_DOMAIN}.
*/
get RP_ORIGIN() {
return `https://${this.RP_DOMAIN}`;
}
/**
* Generate biometric registration options.
* @param userEmail - The email of the user to generate the options for.
* @param alreadyRegisteredCredentials - Any already registered credentials of the user to avoid duplication.
* @returns The generated registration options.
*/
async generateRegistrationOptions(userEmail, alreadyRegisteredCredentials) {
var _a;
const res = await webauthn_utilities_1.WebauthnUtilities.generateRegistrationOptions({
rpName: this.RP_NAME,
rpID: this.RP_DOMAIN,
userName: userEmail,
// Prompt users for additional information about the authenticator.
attestationType: 'none',
// Prevent users from re-registering existing authenticators
excludeCredentials: alreadyRegisteredCredentials.map(c => {
return {
id: c.credentialId
};
}),
authenticatorSelection: {
// Defaults
residentKey: 'preferred',
userVerification: 'preferred'
}
});
return {
...res,
challenge: res.challenge,
excludeCredentials: (_a = res.excludeCredentials) === null || _a === void 0 ? void 0 : _a.map(ec => {
return {
...ec,
id: ec.id
};
})
};
}
/**
* Verifies a biometric registration.
* @param body - The request body including the data to verify (challenge, etc.).
* @param expectedChallenge - The expected challenge.
* @returns The verified biometric registration response.
*/
async verifyRegistrationResponse(body, expectedChallenge) {
if (!expectedChallenge) {
throw new rest_1.HttpErrors.BadRequest(this.NO_REGISTRATION_WITH_PROVIDED_CHALLENGE_FOUND_ERROR_MESSAGE);
}
const res = await webauthn_utilities_1.WebauthnUtilities.verifyRegistrationResponse({
response: body,
expectedChallenge: expectedChallenge,
expectedOrigin: this.RP_ORIGIN,
expectedRPID: this.RP_DOMAIN
});
return {
...res,
registrationInfo: res.registrationInfo == undefined
? undefined
: {
...res.registrationInfo,
credentialID: res.registrationInfo.credentialID,
credentialPublicKey: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString(res.registrationInfo.credentialPublicKey),
attestationObject: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString(res.registrationInfo.attestationObject),
authenticatorExtensionResults: res.registrationInfo.authenticatorExtensionResults == undefined
? undefined
: this.transformAuthenticatorExtensionResults(res.registrationInfo.authenticatorExtensionResults)
}
};
}
/**
* Transforms the given authenticatorExtensionResults to an easier to use structure that uses base64 url strings instead of Uint8Arrays.
* @param authenticatorExtensionResults - The original extension results to transform.
* @returns The transformed value.
*/
transformAuthenticatorExtensionResults(authenticatorExtensionResults) {
var _a, _b, _c, _d;
return {
...authenticatorExtensionResults,
devicePubKey: {
...authenticatorExtensionResults.devicePubKey,
dpk: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString((_a = authenticatorExtensionResults.devicePubKey) === null || _a === void 0 ? void 0 : _a.dpk),
nonce: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString((_b = authenticatorExtensionResults.devicePubKey) === null || _b === void 0 ? void 0 : _b.nonce),
scope: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString((_c = authenticatorExtensionResults.devicePubKey) === null || _c === void 0 ? void 0 : _c.scope),
aaguid: webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString((_d = authenticatorExtensionResults.devicePubKey) === null || _d === void 0 ? void 0 : _d.aaguid)
},
uvm: authenticatorExtensionResults.uvm == undefined
? undefined
: {
uvm: authenticatorExtensionResults.uvm.uvm == undefined
? undefined
: authenticatorExtensionResults.uvm.uvm.map(u => webauthn_utilities_1.WebauthnUtilities.uint8ToBase64UrlString(u))
}
};
}
/**
* Generates authentication options from the provided biometric credentials.
* @param credentialsOfUser - The credentials to generate the options for.
* @returns The generated authentication options.
*/
async generateAuthenticationOptions(credentialsOfUser) {
var _a;
const res = await webauthn_utilities_1.WebauthnUtilities.generateAuthenticationOptions({
rpID: this.RP_DOMAIN,
allowCredentials: credentialsOfUser
});
return {
...res,
challenge: res.challenge,
allowCredentials: (_a = res.allowCredentials) === null || _a === void 0 ? void 0 : _a.map(c => {
return {
...c,
id: c.id
};
})
};
}
/**
* Verify that the user has legitimately completed the authentication process.
* @param body - The response from the frontend.
* @param biometricCredential - The biometric credential that the user tries to login with.
* @returns The verified authentication response.
*/
async verifyAuthenticationResponse(body, biometricCredential) {
return webauthn_utilities_1.WebauthnUtilities.verifyAuthenticationResponse({
response: body,
expectedChallenge: biometricCredential.challenge,
expectedOrigin: `https://${this.RP_DOMAIN}`,
expectedRPID: this.RP_DOMAIN,
authenticator: {
credentialID: biometricCredential.credentialId,
credentialPublicKey: webauthn_utilities_1.WebauthnUtilities.base64UrlStringToUint8(biometricCredential.publicKey),
counter: biometricCredential.counter
}
});
}
}
exports.BaseBiometricCredentialsService = BaseBiometricCredentialsService;
//# sourceMappingURL=base-biometric-credentials.service.js.map