From 87a9771f052481dc0dce30e6b7aa7e0021d4f3a7 Mon Sep 17 00:00:00 2001 From: Felipe Freitag Date: Thu, 9 Jul 2026 15:25:23 -0300 Subject: [PATCH 1/2] feat: add OAuth grants support Add Resend::OAuthGrants with list and remove methods, wrapping the two new OAuth endpoints: - GET /oauth/grants - DELETE /oauth/grants/:oauth_grant_id list supports the standard pagination params (limit, after, before) via PaginationHelper. Includes specs and an example. --- examples/oauth_grants.rb | 28 ++++++++++++++ lib/resend.rb | 1 + lib/resend/oauth_grants.rb | 20 ++++++++++ spec/oauth_grants_spec.rb | 77 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 examples/oauth_grants.rb create mode 100644 lib/resend/oauth_grants.rb create mode 100644 spec/oauth_grants_spec.rb diff --git a/examples/oauth_grants.rb b/examples/oauth_grants.rb new file mode 100644 index 0000000..fbcf697 --- /dev/null +++ b/examples/oauth_grants.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative "../lib/resend" + +raise if ENV["RESEND_API_KEY"].nil? + +Resend.api_key = ENV["RESEND_API_KEY"] + +def list + grants = Resend::OAuthGrants.list + puts grants +end + +def list_paginated + paginated_grants = Resend::OAuthGrants.list({ limit: 10, after: "grant_id_here" }) + puts "Paginated response:" + puts paginated_grants + puts "Has more: #{paginated_grants[:has_more]}" if paginated_grants[:has_more] +end + +def remove + grant = Resend::OAuthGrants.remove("oauth_grant_id_here") + puts grant +end + +list +# list_paginated +# remove diff --git a/lib/resend.rb b/lib/resend.rb index d71388b..9db5211 100644 --- a/lib/resend.rb +++ b/lib/resend.rb @@ -33,6 +33,7 @@ require "resend/logs" require "resend/topics" require "resend/webhooks" +require "resend/oauth_grants" require "resend/automations" require "resend/automations/runs" require "resend/events" diff --git a/lib/resend/oauth_grants.rb b/lib/resend/oauth_grants.rb new file mode 100644 index 0000000..37b9b89 --- /dev/null +++ b/lib/resend/oauth_grants.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Resend + # oauth grants api wrapper + module OAuthGrants + class << self + # https://resend.com/docs/api-reference/oauth/list-grants + def list(params = {}) + path = Resend::PaginationHelper.build_paginated_path("oauth/grants", params) + Resend::Request.new(path, {}, "get").perform + end + + # https://resend.com/docs/api-reference/oauth/revoke-grant + def remove(oauth_grant_id = "") + path = "oauth/grants/#{oauth_grant_id}" + Resend::Request.new(path, {}, "delete").perform + end + end + end +end diff --git a/spec/oauth_grants_spec.rb b/spec/oauth_grants_spec.rb new file mode 100644 index 0000000..c4add3d --- /dev/null +++ b/spec/oauth_grants_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +RSpec.describe "OAuth Grants" do + shared_examples "oauth grants api" do + describe "list" do + it "should list oauth grants" do + resp = { + "object": "list", + "has_more": false, + "data": [ + { + "id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e", + "client_id": "client_123", + "scopes": ["emails:send"], + "resource": nil, + "created_at": "2023-04-21T01:31:02.671414+00:00", + "revoked_at": nil, + "revoked_reason": nil, + "client": { + "name": "My App", + "logo_uri": "https://example.com/logo.png" + } + } + ] + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + grants = Resend::OAuthGrants.list + expect(grants[:data].length).to eql(1) + expect(grants[:data].first[:id]).to eql("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") + expect(grants[:has_more]).to be(false) + end + + it "should build a paginated path" do + expect(Resend::PaginationHelper).to receive(:build_paginated_path) + .with("oauth/grants", { limit: 10 }) + .and_return("oauth/grants?limit=10") + allow_any_instance_of(Resend::Request).to receive(:perform).and_return({}) + Resend::OAuthGrants.list({ limit: 10 }) + end + end + + describe "remove" do + it "should revoke an oauth grant" do + resp = { + "object": "oauth_grant", + "id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e", + "revoked_at": "2023-04-22T10:00:00.000000+00:00", + "revoked_reason": "user_requested" + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + grant = Resend::OAuthGrants.remove("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") + expect(grant[:id]).to eql("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") + expect(grant[:revoked_reason]).to eql("user_requested") + end + end + end + + context "static api_key" do + before do + Resend.configure do |config| + config.api_key = "re_123" + end + end + + include_examples "oauth grants api" + end + + context "dynamic api_key" do + before do + Resend.configure do |config| + config.api_key = -> { "re_123" } + end + end + + include_examples "oauth grants api" + end +end From 547f316c04d5cd9448ba34708b3f7da6990eb24d Mon Sep 17 00:00:00 2001 From: Felipe Freitag Date: Thu, 9 Jul 2026 15:39:01 -0300 Subject: [PATCH 2/2] refactor: rename OAuthGrants.remove to revoke Match the Node SDK's method name (per review feedback). --- examples/oauth_grants.rb | 6 +++--- lib/resend/oauth_grants.rb | 2 +- spec/oauth_grants_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/oauth_grants.rb b/examples/oauth_grants.rb index fbcf697..12ebd22 100644 --- a/examples/oauth_grants.rb +++ b/examples/oauth_grants.rb @@ -18,11 +18,11 @@ def list_paginated puts "Has more: #{paginated_grants[:has_more]}" if paginated_grants[:has_more] end -def remove - grant = Resend::OAuthGrants.remove("oauth_grant_id_here") +def revoke + grant = Resend::OAuthGrants.revoke("oauth_grant_id_here") puts grant end list # list_paginated -# remove +# revoke diff --git a/lib/resend/oauth_grants.rb b/lib/resend/oauth_grants.rb index 37b9b89..59ff683 100644 --- a/lib/resend/oauth_grants.rb +++ b/lib/resend/oauth_grants.rb @@ -11,7 +11,7 @@ def list(params = {}) end # https://resend.com/docs/api-reference/oauth/revoke-grant - def remove(oauth_grant_id = "") + def revoke(oauth_grant_id = "") path = "oauth/grants/#{oauth_grant_id}" Resend::Request.new(path, {}, "delete").perform end diff --git a/spec/oauth_grants_spec.rb b/spec/oauth_grants_spec.rb index c4add3d..cb17f42 100644 --- a/spec/oauth_grants_spec.rb +++ b/spec/oauth_grants_spec.rb @@ -39,7 +39,7 @@ end end - describe "remove" do + describe "revoke" do it "should revoke an oauth grant" do resp = { "object": "oauth_grant", @@ -48,7 +48,7 @@ "revoked_reason": "user_requested" } allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) - grant = Resend::OAuthGrants.remove("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") + grant = Resend::OAuthGrants.revoke("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") expect(grant[:id]).to eql("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") expect(grant[:revoked_reason]).to eql("user_requested") end