Class: AtprotoAuth::PAR::ClientAssertion

Inherits:
Object
  • Object
show all
Defined in:
lib/atproto_auth/par/client_assertion.rb

Overview

Generates client authentication JWTs according to RFC 7523 for AT Protocol OAuth. Creates signed assertions using ES256 with required claims including iss/sub (client_id), aud (token endpoint), jti (unique ID), and iat/exp (timing claims).

Defined Under Namespace

Classes: Error

Instance Method Summary collapse

Constructor Details

#initialize(client_id:, signing_key:) ⇒ ClientAssertion

Returns a new instance of ClientAssertion.

Parameters:

  • client_id (String)

    OAuth client ID

  • signing_key (JOSE::JWK)

    Key to sign assertion with



13
14
15
16
# File 'lib/atproto_auth/par/client_assertion.rb', line 13

def initialize(client_id:, signing_key:)
  @client_id = client_id
  @signing_key = signing_key
end

Instance Method Details

#generate_jwt(audience:, lifetime: 300) ⇒ String

Generates a new client assertion JWT 5 minute default lifetime

Parameters:

  • audience (String)

    Issuer endpoint URL

  • lifetime (Integer) (defaults to: 300)

    How long assertion is valid for in seconds

Returns:

  • (String)

    Signed JWT assertion



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
# File 'lib/atproto_auth/par/client_assertion.rb', line 23

def generate_jwt(audience:, lifetime: 300)
  now = Time.now.to_i

  payload = {
    # Required claims
    iss: @client_id, # Issuer is client_id
    sub: @client_id, # Subject is client_id
    aud: audience, # Audience is token endpoint
    jti: SecureRandom.uuid, # Unique identifier
    exp: now + lifetime, # Expiration time
    iat: now # Issued at time
  }

  # Header specifying ES256 algorithm for signing
  header = {
    alg: "ES256",
    typ: "JWT",
    kid: @signing_key.fields["kid"]
  }

  # Sign and return the JWT
  JWT.encode(payload, @signing_key.kty.key, "ES256", header)
rescue StandardError => e
  raise Error, "Failed to generate client assertion: #{e.message}"
end