diff --git a/packages/api/src/functions/dbAuth/DbAuthHandler.ts b/packages/api/src/functions/dbAuth/DbAuthHandler.ts index ece793c7373b..f5858a464b59 100644 --- a/packages/api/src/functions/dbAuth/DbAuthHandler.ts +++ b/packages/api/src/functions/dbAuth/DbAuthHandler.ts @@ -7,6 +7,10 @@ import type { VerifiedRegistrationResponse, VerifiedAuthenticationResponse, } from '@simplewebauthn/server' +import type { + AuthenticationCredentialJSON, + RegistrationCredentialJSON, +} from '@simplewebauthn/typescript-types' import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' import base64url from 'base64url' import CryptoJS from 'crypto-js' @@ -229,12 +233,13 @@ export type AuthMethodNames = | 'webAuthnAuthOptions' | 'webAuthnAuthenticate' -type Params = { - username?: string - password?: string - method: AuthMethodNames - [key: string]: any -} +type Params = AuthenticationCredentialJSON & + RegistrationCredentialJSON & { + username?: string + password?: string + method: AuthMethodNames + [key: string]: any + } /** * To use in src/lib/auth#getCurrentUser @@ -705,9 +710,8 @@ export class DbAuthHandler> { throw new DbAuthError.WebAuthnError('WebAuthn is not enabled') } - const jsonBody = JSON.parse(this.event.body as string) const credential = await this.dbCredentialAccessor.findFirst({ - where: { id: jsonBody.rawId }, + where: { id: this.params.rawId }, }) if (!credential) { @@ -724,7 +728,7 @@ export class DbAuthHandler> { let verification: VerifiedAuthenticationResponse try { const opts: VerifyAuthenticationResponseOpts = { - credential: jsonBody, + credential: this.params, expectedChallenge: user[this.options.authFields.challenge as string], expectedOrigin: webAuthnOptions.origin, expectedRPID: webAuthnOptions.domain, @@ -772,7 +776,7 @@ export class DbAuthHandler> { // get the regular `login` cookies const [, loginHeaders] = this._loginResponse(user) const cookies = [ - this._webAuthnCookie(jsonBody.rawId, this.webAuthnExpiresDate), + this._webAuthnCookie(this.params.rawId, this.webAuthnExpiresDate), loginHeaders['set-cookie'], ].flat() @@ -897,12 +901,11 @@ export class DbAuthHandler> { } const user = await this._getCurrentUser() - const jsonBody = JSON.parse(this.event.body as string) let verification: VerifiedRegistrationResponse try { const options: VerifyRegistrationResponseOpts = { - credential: jsonBody, + credential: this.params, expectedChallenge: user[this.options.authFields.challenge as string], expectedOrigin: this.options.webAuthn.origin, expectedRPID: this.options.webAuthn.domain, @@ -935,8 +938,10 @@ export class DbAuthHandler> { user[this.options.authFields.id], [this.options.webAuthn.credentialFields.publicKey]: credentialPublicKey, - [this.options.webAuthn.credentialFields.transports]: - jsonBody.transports ? JSON.stringify(jsonBody.transports) : null, + [this.options.webAuthn.credentialFields.transports]: this.params + .transports + ? JSON.stringify(this.params.transports) + : null, [this.options.webAuthn.credentialFields.counter]: counter, }, }) diff --git a/packages/api/src/functions/dbAuth/__tests__/DbAuthHandler.test.js b/packages/api/src/functions/dbAuth/__tests__/DbAuthHandler.test.js index 876d4e2bb236..deac5d412ad9 100644 --- a/packages/api/src/functions/dbAuth/__tests__/DbAuthHandler.test.js +++ b/packages/api/src/functions/dbAuth/__tests__/DbAuthHandler.test.js @@ -1833,6 +1833,35 @@ describe('dbAuth', () => { expect(credential.transports).toEqual('["internal"]') expect(credential.counter).toEqual(0) }) + + it('works if event body is base64 encoded', async () => { + const user = await createDbUser({ + webAuthnChallenge: 'HuGPrQqK7f53NLwMZMst_DL9Dig2BBivDYWWpawIPVM', + }) + event = { + headers: { + 'Content-Type': 'application/json', + cookie: encryptToCookie( + JSON.stringify({ id: user.id }) + ';' + 'token' + ), + }, + body: Buffer.from( + `{"method":"webAuthnRegister","id":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","rawId":"GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg","response":{"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVisSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAKBqo2TrmGKaTmwQ3lZJ263AS5GmvYpkuRCScLQle-NGrFM9uLHQJhhalAQIDJiABIVggGIipTQt-gcoDPOpW6Zje_Av9C0-jWb2R2PBmXJJL-c8iWCC76wxo3uzG8cPqb0A8Vij-dqMbrEytEHjuFOtiQ2dt8A","clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSHVHUHJRcUs3ZjUzTkx3TVpNc3RfREw5RGlnMkJCaXZEWVdXcGF3SVBWTSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODkxMCIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9"},"type":"public-key","clientExtensionResults":{},"transports":["internal"]}`, + 'utf8' + ), + } + const dbAuth = new DbAuthHandler(event, context, options) + + await dbAuth.webAuthnRegister() + + const credential = db.userCredential.findFirst({ + where: { userId: user.id }, + }) + + expect(credential.id).toEqual( + 'GqjZOuYYppObBDeVknbrcBLkaa9imS5EJJwtCV740asUz24sdAmGFg' + ) + }) }) describe('_validateOptions', () => {