Better Auth Utils

repository·main·Indexed 42 days ago

https://github.com/better-auth/utils

A TypeScript library providing unified, high-level APIs for common authentication-related cryptographic tasks. It leverages Web Crypto APIs for compatibility across Node.js and web environments, offering utilities for hashing (SHA, scrypt), HMAC, RSA/ECDSA asymmetric encryption, OTP generation (HOTP and TOTP), and various encoding formats including Base32, Base64, and Hexadecimal. Version 0.5.0.

Tokens
7.7K
Snippets
39
Records
39
Agent score
50%

What's inside Better Auth Utils

  1. Encode and decode Base64

    main

    Use base64 for standard encoding or base64Url for URL-safe encoding.

    • Standard Base64: base64.encode(data, { padding, url }) and base64.decode(encodedData).
    • Base64Url: base64Url.encode(data) for a URL-safe alternative.
    import { base64 } from "@better-auth/utils/base64";
    import { base64Url } from "@better-auth/utils/base64";
    
    // Standard
    const encoded = base64.encode("Data", { url: true, padding: false });
    const decoded = await base64.decode(encoded);
    
    // URL Safe
    const urlSafeEncoded = base64Url.encode("Data");
  2. Use HMAC for secure signing and verification

    main

    The HMAC utility allows you to securely hash data using a secret key.

    1. Create an instance: Use createHMAC(algorithm, encoding) where algorithm is SHA-256, SHA-384, or SHA-512 and encoding can be none, hex, base64, base64url, or base64urlnopad.
    2. Import a key: Use hmac.importKey(secretKey) to convert a string, buffer, or typed array into a CryptoKey.
    3. Sign: Use hmac.sign(key, data) or pass a raw secret string directly to hmac.sign(secret, { data: '...' }).
    4. Verify: Use hmac.verify(key, data, signature) to check if a signature is valid.
    import { createHMAC } from './hmac';
    
    const hmac = createHMAC("SHA-256", "hex");
    const secretKey = "my-secret-key";
    
    // Using imported key
    const key = await hmac.importKey(secretKey);
    const signature = await hmac.sign(key, "text to sign");
    const isValid = await hmac.verify(key, "text to sign", signature);
    
    // Direct signing with raw string
    const signature2 = await hmac.sign("secret-key", {
        data: "text"
    });
  3. Generate and verify OTP (HOTP and TOTP)

    main

    The OTP utility supports both HOTP (RFC 4226) and TOTP (RFC 6238) standards.

    • HOTP: Requires a secret and a counter. Use createOTP(secret, options).hotp(counter).
    • TOTP: Requires a secret and a time period. Use createOTP(secret, options).totp().
    • Verification: Use .verify(otp, { window }) to check a code. The window option allows for clock drift compensation.
    • Authenticator URLs: Use .url(issuer, account) to generate a provisioning URL for apps like Google Authenticator.
    import { createOTP } from "@better-auth/utils/otp";
    const secret = "my-super-secret-key";
    
    // HOTP
    const hotp = createOTP(secret, { digits: 6 }).hotp(1234);
    
    // TOTP
    const totpInstance = createOTP(secret, { digits: 6, period: 30 });
    const otp = totpInstance.totp();
    const isValid = totpInstance.verify(otp, { window: 60 });
    
    // Authenticator URL
    const qrCodeUrl = createOTP(secret).url("my-app", "user@email.com");
  4. Perform ECDSA signing and verification

    main

    ECDSA utilities allow for elliptic curve cryptography operations.

    • Key Generation: ecdsa.generateKeyPair(curve) where curves are P-256, P-384, or P-521.
    • Export/Import: ecdsa.exportKey(key, format) (e.g., pkcs8, spki) and ecdsa.importPrivateKey(key, curve) / ecdsa.importPublicKey(key, curve).
    • Signing: ecdsa.sign(privateKey, data, hash) (default hash: SHA-256).
    • Verification: ecdsa.verify(publicKey, { signature, data, hash }).
    import { ecdsa } from "@better-auth/utils/ecdsa";
    
    // Key Pair Generation
    const { privateKey, publicKey } = await ecdsa.generateKeyPair("P-256");
    
    // Signing
    const signature = await ecdsa.sign(privateKey, "Message to sign", "SHA-256");
    
    // Verifying
    const isValid = await ecdsa.verify(publicKey, {
      signature,
      data: "Message to verify",
      hash: "SHA-256",
    });
  5. Encode and decode Hexadecimal

    main

    Use hex to convert between strings/buffers and hexadecimal representations.

    • Encoding: hex.encode(data).
    • Decoding: hex.decode(encodedData).
    • Bytes Conversion: hex.toBytes(hexString) converts a hex string into a Uint8Array. This is recommended when the hex represents raw binary data (like signatures) rather than UTF-8 text.
    import { hex } from "@better-auth/utils/hex";
    
    const encoded = hex.encode("Data");
    const decoded = hex.decode(encoded);
    const bytes = hex.toBytes("48656c6c6f"); // Uint8Array([72, 101, 108, 108, 111])
  6. Generate random strings

    main

    Create a cryptographically secure random string generator by specifying a charset. You can then generate strings of a specific length or override the charset during generation.

    import { createRandomStringGenerator } from "@better-auth/utils/random"
    
    // 1. Create generator with specific charset
    export const generateRandomString = createRandomStringGenerator("A-Z", "0-9", "a-z", "-_") 
    
    // 2. Generate string of length 32
    const randomString = generateRandomString(32)
    
    // 3. Override charset for a specific call
    const randomString2 = generateRandomString(32, "A-Z", "0-9")
  7. Hash data using createHash

    main

    Use createHash to generate digests using the SHA family of hash functions. You can specify the encoding for the output (e.g., hex or base64).

    import { createHash } from "@better-auth/utils/hash"
    
    const hashBuffer = await createHash("SHA-256").digest("text");
    const hashInHex = await createHash("SHA-256", "hex").digest("text");
    const hashInBase64 = await createHash("SHA-256", "base64").digest("text");
  8. Perform RSA encryption and signing

    main

    RSA utilities provide high-level methods for asymmetric cryptography.

    • Key Generation: rsa.generateKeyPair(modulusLength, hashAlgorithm) (default: 2048 bits, SHA-256).
    • Export/Import: Use rsa.exportKey(key, format) (e.g., jwk, spki) and rsa.importKey(key, usage) (e.g., encrypt, decrypt, sign, verify).
    • Encryption/Decryption: rsa.encrypt(publicKey, data) and rsa.decrypt(privateKey, encryptedData).
    • Signing/Verification: rsa.sign(privateKey, data) and rsa.verify(publicKey, { signature, data }).
    import { rsa } from "@better-auth/utils/rsa";
    
    // Key Pair Generation
    const keyPair = await rsa.generateKeyPair(2048, "SHA-256");
    const { publicKey, privateKey } = keyPair;
    
    // Encryption/Decryption
    const encryptedData = await rsa.encrypt(publicKey, "Sensitive data");
    const decryptedData = await rsa.decrypt(privateKey, encryptedData);
    
    // Signing/Verification
    const signature = await rsa.sign(privateKey, "Message to sign");
    const isValid = await rsa.verify(publicKey, {
      signature,
      data: "Message to sign",
    });
  9. Encode and decode Binary data

    main

    The binary utility uses TextEncoder and TextDecoder to convert strings to Uint8Array and vice versa.

    import { binary } from "@better-auth/util/binary"
    
    const data = binary.encode("Hello World!");
    const decoded = binary.decode(new Uint8Array([72, 101, 108, 108, 111]));
  10. Generate RSA key pairs

    main

    Use rsa.generateKeyPair to create a new RSA key pair for encryption/decryption. By default, it generates a 2048-bit key using the SHA-256 hash algorithm. Supported modulus lengths are 2048 or 4096.

    import { rsa } from '@better-auth/utils';
    
    const keyPair = await rsa.generateKeyPair(2048, 'SHA-256');
    // keyPair contains the CryptoKey objects for public and private keys
  11. Decode Base64Url encoded data

    main

    Use the base64Url.decode method to convert a Base64Url string back into a Uint8Array. It automatically detects the alphabet based on the presence of URL-safe characters.

    import { base64Url } from "@better-auth/utils";
    
    const decoded = base64Url.decode("aGVsbG8td29ybGQ");
    // Returns a Uint8Array