summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src/authentication/generateAuthenticationOptions.ts
blob: 3847b39df01faa8ffb65cda7ee0d32e710eba301 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import type {
  AuthenticationExtensionsClientInputs,
  PublicKeyCredentialRequestOptionsJSON,
  PublicKeyCredentialDescriptorFuture,
  UserVerificationRequirement,
} from '@simplewebauthn/typescript-types';

import { isoBase64URL, isoUint8Array } from '../helpers/iso'
import { generateChallenge } from '../helpers/generateChallenge';

export type GenerateAuthenticationOptionsOpts = {
  allowCredentials?: PublicKeyCredentialDescriptorFuture[];
  challenge?: string | Uint8Array;
  timeout?: number;
  userVerification?: UserVerificationRequirement;
  extensions?: AuthenticationExtensionsClientInputs;
  rpID?: string;
};

/**
 * Prepare a value to pass into navigator.credentials.get(...) for authenticator "login"
 *
 * @param allowCredentials Authenticators previously registered by the user, if any. If undefined
 * the client will ask the user which credential they want to use
 * @param challenge Random value the authenticator needs to sign and pass back
 * user for authentication
 * @param timeout How long (in ms) the user can take to complete authentication
 * @param userVerification Set to `'discouraged'` when asserting as part of a 2FA flow, otherwise
 * set to `'preferred'` or `'required'` as desired.
 * @param extensions Additional plugins the authenticator or browser should use during authentication
 * @param rpID Valid domain name (after `https://`)
 */
export function generateAuthenticationOptions(
  options: GenerateAuthenticationOptionsOpts = {},
): PublicKeyCredentialRequestOptionsJSON {
  const {
    allowCredentials,
    challenge = generateChallenge(),
    timeout = 60000,
    userVerification,
    extensions,
    rpID,
  } = options;

  /**
   * Preserve ability to specify `string` values for challenges
   */
   let _challenge = challenge;
   if (typeof _challenge === 'string') {
     _challenge = isoUint8Array.fromUTF8String(_challenge);
   }

  return {
    challenge: isoBase64URL.fromBuffer(_challenge),
    allowCredentials: allowCredentials?.map(cred => ({
      ...cred,
      id: isoBase64URL.fromBuffer(cred.id as Uint8Array),
    })),
    timeout,
    userVerification,
    extensions,
    rpId: rpID,
  };
}