diff --git a/test/privy/integration/jwt_exchange_test.rb b/test/privy/integration/jwt_exchange_test.rb index 18e66a7..e0cd9b3 100644 --- a/test/privy/integration/jwt_exchange_test.rb +++ b/test/privy/integration/jwt_exchange_test.rb @@ -6,6 +6,10 @@ class Privy::Test::Integration::JwtExchangeTest < Privy::Test::IntegrationTest def setup super skip("JWT_AUTH_SK not set") unless ENV["JWT_AUTH_SK"] && !ENV["JWT_AUTH_SK"].empty? + + # /wallets/authenticate (which jwt_exchange wraps) rejects JWTs for users + # that don't own any wallet. Ensure the freshly-minted user has one. + create_user_owned_wallet end def test_exchange_jwt_returns_authorization_key diff --git a/test/privy/integration/services/wallets_test.rb b/test/privy/integration/services/wallets_test.rb index adc0638..0391e8e 100644 --- a/test/privy/integration/services/wallets_test.rb +++ b/test/privy/integration/services/wallets_test.rb @@ -203,8 +203,7 @@ def test_raw_sign_on_p256_owned_wallet_returns_signature def test_raw_sign_on_user_owned_wallet_returns_signature skip("JWT_AUTH_SK not set") unless ENV["JWT_AUTH_SK"] && !ENV["JWT_AUTH_SK"].empty? - user = client.users.get_by_custom_auth_id(custom_user_id: jwt_auth_subject) - wallet = client.wallets.create(wallet_create_params: {chain_type: :tron, owner: {user_id: user.id}}) + wallet = create_user_owned_wallet(chain_type: :tron) jwt = generate_test_jwt ctx = Privy::Authorization::AuthorizationContext.build(user_jwts: [jwt]) diff --git a/test/privy/integration/support/jwt_helpers.rb b/test/privy/integration/support/jwt_helpers.rb index 248342e..4861e5c 100644 --- a/test/privy/integration/support/jwt_helpers.rb +++ b/test/privy/integration/support/jwt_helpers.rb @@ -2,16 +2,26 @@ require "openssl" require "jwt" +require "securerandom" module Privy module Test module Integration module JwtHelpers + # A unique custom-auth subject per test instance. Memoized so the JWT + # `sub` claim and the user's custom_auth_id stay in lockstep within one + # test, while Minitest's per-test instance gives us a fresh value across + # tests and runs. This avoids accumulating wallets under a single shared + # user (which trips the per-user wallet limit on staging). def jwt_auth_subject - ENV.fetch("JWT_AUTH_SUBJECT", "java-sdk-sub-id") + @jwt_auth_subject ||= "ruby-sdk-test-#{SecureRandom.uuid}" end def generate_test_jwt + # Ensure the Privy user exists before handing out a JWT for them; the + # API endpoints that accept these JWTs (e.g. /wallets/authenticate) + # 404 when the subject has never been linked to a user. + jwt_auth_user raw = ENV.fetch("JWT_AUTH_SK") pem = raw.gsub('\n', "\n").gsub("\r", "").strip private_key = OpenSSL::PKey::RSA.new(pem) @@ -19,9 +29,18 @@ def generate_test_jwt JWT.encode(payload, private_key, "RS256", {typ: "JWT"}) end - def create_user_owned_wallet - user = client.users.get_by_custom_auth_id(custom_user_id: jwt_auth_subject) - client.wallets.create(wallet_create_params: {chain_type: :ethereum, owner: {user_id: user.id}}) + # Lazily creates a Privy user backed by a fresh custom-auth subject and + # returns it. Subsequent calls within the same test return the same user. + def jwt_auth_user + @jwt_auth_user ||= client.users.create( + linked_accounts: [{type: :custom_auth, custom_user_id: jwt_auth_subject}] + ) + end + + def create_user_owned_wallet(chain_type: :ethereum) + client.wallets.create( + wallet_create_params: {chain_type: chain_type, owner: {user_id: jwt_auth_user.id}} + ) end end end