danielberkompas/ex_twilio

Support API Keys

kiere opened this issue · 3 comments

kiere commented

In my Twilio project (in the Twilio console), we have the Account SID and Auth Token by default, but we use API Keys to hit the endpoints (for the basic auth portion). Unfortunately, you can't use the API Key SID as the Account SID; you still have to provide the Account SID in the API endpoints. I tried letting the Account SID be set by ENV var and then passing in the account and token options for the API key, but ExTwilio seems to take the account option as the account sid when generating the Endpoint URLs.

Does that sound right? And how much effort do you think it would take to modify the library to allow you to pass the account SID as a config option using ENVs and passing the auth "username" as an option to the command (I'm still using ENV, but doing via Application.get_env/3)?

We may end up using subaccounts (inside a Twilio Project) for our customers, but API Key support would be nice for a more secure devops configuration. (Thinking more like AWS IAM vs using AWS root credentials.)

I don't think this would necessarily require a lot of effort. Probably, you'd just need to extend the library to accept a new option, similar to account. I'm open to PRs for this!

I was wondering about this as well but, at least for sending SMS, this seems to be supported just by passing the :Authorization value as an option. Something like:

credentials = Base.encode64("#{api_sid:api_secret}")
ExTwilio.Message.create(to: "+1XXXXXXXXXX, from: "+1XXXXXXXXXX", body: "Totally auth'd via ExTwilio", Authorization: "Basic #{credentials}")

So maybe not first class support, but possible.

Discovered this by looking here:

def auth_header(headers, {sid, token}) when not is_nil(sid) and not is_nil(token) do
case Keyword.has_key?(headers, :Authorization) do
true ->
headers
false ->
auth = Base.encode64("#{sid}:#{token}")
headers
|> Keyword.put(:Authorization, "Basic #{auth}")
end
end

@objectuser unfortunately it seems there's a slight obstacle preventing this method from working with resource creation calls (such as ExTwilio.Message.create/2) as of today:

When Api.create/3 is called, it will always call auth_header/1 as seen below:

def create(module, data, options \\ []) do
data = format_data(data)
module
|> Url.build_url(nil, options)
|> Api.post!(data, auth_header(options))
|> Parser.parse(module)
end

This, in turn, makes it so that our headers list in auth_header/2 is always empty:

@spec auth_header(options :: list) :: list
def auth_header(options \\ []) do
auth_header([], {options[:account], options[:token]})
end

Because of this, the Authorization header never gets overridden in the request.. ☹️