Module: AtprotoAuth::PKCE

Defined in:
lib/atproto_auth/pkce.rb

Overview

Implementation of Proof Key for Code Exchange (PKCE) for OAuth 2.0 / AT Protocol as specified in RFC 7636.

This module provides functionality to:

  • Generate cryptographically secure code verifiers

  • Create SHA-256 code challenges from verifiers

  • Verify challenge/verifier pairs

Only the S256 challenge method is supported, as required by AT Protocol OAuth.

Defined Under Namespace

Classes: Error

Constant Summary collapse

MIN_VERIFIER_LENGTH =

Minimum and maximum lengths for code verifier as per RFC 7636

43
MAX_VERIFIER_LENGTH =
128
ALLOWED_VERIFIER_CHARS =

PKCE code verifier charset as per RFC 7636 Section 4.1

/^[A-Za-z0-9\-\._~]+$/

Class Method Summary collapse

Class Method Details

.generate_challenge(verifier) ⇒ String

Creates a code challenge from a verifier using SHA-256

Parameters:

  • verifier (String)

    The code verifier to create challenge from

Returns:

  • (String)

    Base64URL-encoded SHA-256 hash of the verifier

Raises:

  • (Error)

    if verifier is invalid or hashing fails



47
48
49
50
51
52
53
54
55
# File 'lib/atproto_auth/pkce.rb', line 47

def generate_challenge(verifier)
  validate_verifier!(verifier)

  # Hash with SHA-256 and encode as URL-safe base64
  digest = OpenSSL::Digest::SHA256.digest(verifier)
  Base64.urlsafe_encode64(digest, padding: false)
rescue StandardError => e
  raise Error, "Failed to generate challenge: #{e.message}"
end

.generate_verifier(length = MAX_VERIFIER_LENGTH) ⇒ String

Generates a cryptographically secure random code verifier

Parameters:

  • length (Integer) (defaults to: MAX_VERIFIER_LENGTH)

    Length of verifier to generate

Returns:

  • (String)

    The generated code verifier

Raises:

  • (Error)

    if length is invalid



33
34
35
36
37
38
39
40
41
# File 'lib/atproto_auth/pkce.rb', line 33

def generate_verifier(length = MAX_VERIFIER_LENGTH)
  validate_verifier_length!(length)

  # Generate random bytes and encode as URL-safe base64
  random_bytes = SecureRandom.random_bytes(length * 3 / 4)
  Base64.urlsafe_encode64(random_bytes, padding: false)[0...length]
rescue StandardError => e
  raise Error, "Failed to generate verifier: #{e.message}"
end

.verify(challenge, verifier) ⇒ Boolean

Verifies that a challenge matches a verifier

Parameters:

  • challenge (String)

    The code challenge to verify

  • verifier (String)

    The code verifier to check against

Returns:

  • (Boolean)

    true if challenge matches verifier

Raises:

  • (Error)

    if inputs are invalid



62
63
64
65
66
67
68
69
70
71
# File 'lib/atproto_auth/pkce.rb', line 62

def verify(challenge, verifier)
  # Generate challenge from verifier and compare
  calculated = generate_challenge(verifier)
  secure_compare(calculated, challenge)
rescue Error
  # Re-raise PKCE errors
  raise
rescue StandardError => e
  raise Error, "Challenge verification failed: #{e.message}"
end