Closed epinault closed 6 years ago
Hi, thanks for the first github issue!
Authorization grant flow (or "web server flow" as in salesforce doc) requires callback phase, which is out of scope of this project, which is for very thin layer.
Once you get an access token after the oauth dance, you can just build new ExForce.Config
and pass it to all functions, to call Salesforce API on the behalf of the authenticated user.
If I need the feature, I'd write a oauth2 library wrapper for salesforce oauth, and then write a ueberauth strategy with it.
I am less concern I guess about the web server flow really than just being able to connect using the Oauth Token ( have have the flow down out side of this library). But then I could not figure out how to pass the Oauth token in the config. I ll try that file you have to see if I can get it to work.
I ll take a look at the Oauth2 Lib so I can support refresh token too but I agree that it might not be needed in this lib . thanks for the prompt reply ! this lib looks very promising!
Here is how you can use oauth2
library.
defmodule Test do
def client_opts do
[
site: System.get_env("SALESFORCE_SITE"),
client_id: System.get_env("SALESFORCE_CLIENT_ID"),
client_secret: System.get_env("SALESFORCE_CLIENT_SECRET"),
authorize_url: "/services/oauth2/authorize",
token_url: "/services/oauth2/token"
]
end
def test_password do
password_opts = [
username: System.get_env("SALESFORCE_USERNAME"),
password: System.get_env("SALESFORCE_PASSWORD") <> System.get_env("SALESFORCE_SECURITY_TOKEN")
]
client =
client_opts()
|> Keyword.put(:strategy, OAuth2.Strategy.Password)
|> OAuth2.Client.new()
|> OAuth2.Client.put_header("Accept", "application/json")
{:ok, client} = OAuth2.Client.get_token(client, password_opts)
true = verify_signature(client)
IO.inspect client
end
def test_auth_code do
# put redirect uri as configured in Salesforce
redirect_uri = "http://localhost:4000/auth/salesforce/callback"
client =
client_opts()
|> Keyword.put(:strategy, OAuth2.Strategy.AuthCode)
|> Keyword.put(:redirect_uri, redirect_uri)
|> OAuth2.Client.new()
|> OAuth2.Client.put_header("Accept", "application/json")
# open this URL in browser
IO.puts OAuth2.Client.authorize_url!(client)
# put urldecoded auth code here
auth_code = "..."
client
# when "Require Secret for Web Server Flow" option is checked
|> OAuth2.Client.put_param(:client_secret, client.client_secret)
|> OAuth2.Client.get_token(code: auth_code)
|> IO.inspect
end
def test_refresh do
# client must be configured with "Perform requests on your behalf at any time (refresh_token, offline_access)"
client =
client_opts()
|> Keyword.put(:strategy, OAuth2.Strategy.Refresh)
|> OAuth2.Client.new()
|> OAuth2.Client.put_header("Accept", "application/json")
refresh_token = "..."
client
# when "Require Secret for Web Server Flow" option is checked
|> OAuth2.Client.put_param(:client_secret, client.client_secret)
|> OAuth2.Client.get_token(refresh_token: refresh_token)
|> IO.inspect
end
# Base64-encoded HMAC-SHA256 signature signed with the consumer's private key containing the concatenated ID and issued_at value. The signature can be used to verify that the identity URL wasn’t modified because it was sent by the server.
def verify_signature(%OAuth2.Client{client_secret: client_secret, token: %OAuth2.AccessToken{other_params: %{"id" => id, "issued_at" => issued_at, "signature" => signature}}}) do
calculated =
:sha256
|> :crypto.hmac(client_secret, id <> issued_at_raw)
|> Base.encode64()
calculated == signature
end
end
I'm going to write oauth2_force
(maybe without oauth2 dependency?), and refactor ex_force
so that it use oauth2_force
for authentication, or just use accept access token.
...or just make it part of ex_force
.
Please take a look at #2 :)
master
branch now has ExForce.OAuth
to handle different type of grant type. Still you need to get authorization code or refresh token and pass it to ExForce
.
cool! thanks!
do you support username-password flow only? Or do you also support web server flow?