How should I use webclient for oauth 2.0? - oauth-2.0

I handled a lot of API from many exchanges.
I want the API to work without user intervention.
Usually, I wrote codes like this
Dim timestamp = getEstimatedServerTimeStamp().ToString
Dim domain = "https://api.kucoin.com"
Dim endpoint = "/api/v1/" + method
Dim stringtosign = timestamp + "GET" + endpoint '1553106384182GET/api/v1/accounts
'Dim secretandpassphrase = _secret1.Split("|"c)
'Dim secret = secretandpassphrase(0) 'a7c38ae4-b6e3-4254-b78c-*******
'Dim passphrase = secretandpassphrase(1) '7Q5eVqOw*******
Dim hasher = New System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(_secret1))
Dim sighashbyte = hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringtosign))
Dim sighash = System.Convert.ToBase64String(sighashbyte)
Dim url = domain + endpoint 'url https://api.kucoin.com/api/v1/accounts
Dim response = CookieAwareWebClient.downloadString1(url, "", {Tuple.Create("KC-API-SIGN", sighash), Tuple.Create("KC-API-TIMESTAMP", timestamp), Tuple.Create("KC-API-KEY", _apiKey1), Tuple.Create("KC-API-PASSPHRASE", _passphrase1)})
Return response
So I am using the secret and the API key.
However, at Sstex, something is different.
First, they told me to register a client and a redirect URL. What does redirect URL mean?
I tried
going to https://apidocs.stex.com/#/Profile/get_profile_wallets
to try some demo.
It turns out I can see my wallet content without using my API key and secret at all. Instead of API key and secret I authorize here
https://apidocs.stex.com/#/Profile/get_profile_wallets
Then I can see my balances.
So I tried some similar code after looking on the web
I did
If token = "" Then
Dim token1 = CookieAwareWebClient.downloadString1("https://app.stex.com/oauth/authorize?client_id=1**&client_secret=3vmEisPCGekF1JGePkwdSKdf4Q00lJTKmwxh****")
End If
Instead of json I am getting an html.
So I wonder.
What exactly I should do with OAuth? Is it designed for something different than regular API access?
The manual says I should curl things like
curl -X GET "https://api3.stex.com/profile/wallets?sort=DESC&sortBy=BALANCE" -H "accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjY1NzUyODQwYmMzMmMwNGU0MTExNmRmYjQ0M2I5NWY4NzAzYmVkYWIyNTk0ZWZhMTg3ZjhhMmQxOThiNzM1NGRkNThjZmYzYWJkZWEzZjg5In0.eyJhdWQiOiIxNDIiLCJqdGkiOiI2NTc1Mjg0MGJjMzJjMDRlNDExMTZkZmI0NDNiOTVmODcwM2JlZGFiMjU5NGVmYTE4N2Y4YTJkMTk4YjczNTRkZDU4Y2ZmM2FiZGVhM2Y4OSIsImlhdCI6MTU1MzI4NTc4NiwibmJmIjoxNTUzMjg1Nzg2LCJleHAiOjE1NTMzMjg5ODYsInN1YiI6IjMxOTgwMSIsInNjb3BlcyI6WyJwcm9maWxlIiwicmVwb3J0cyIsInRyYWRlIl19.aRuu1gmUmpcck_rMh9fcQwfDeJezn0tD0v1aSJ7joIhtsIXAdaw0H-SFOXwzo_HevFrcDnWGrZ4s9sTd1_vgRS2or7HyiV54c0ItVym6bOMKnFhGuxWWLubXN9HstjiM9TSghk7FtF5J0XeIDcY4vp25ycBmWM6Dddeyu4ehu3hurG-jUyT9N1C4u5KwqkYazeE1Z6XpCUrH77tAIlecTssPUzDtM6j-dYJOirYLx-E7fTn6H_bpHq_mosiHEy7IGe2uyggx0UIg4YIIX0noATxNfFiqZlXc32u8NywS7bDkFJ8e4s2r6vbL9pZU7Qe81IFrhs2jgUrQyjxe4SKsyolA9SulwF1haqsRGYTN_fNZyNm7u_Nzs2-RWxZw7h5KHT48AI483bHqJS3qfpjNF7FdpEufnn1QuFplumvyATtlEf56RCTfZ11fWjaET_b19P_3KpJw8H3pYSh8f-7MdIJcn68X1ls_9GahKKlX059I2M_6S2XkjwvnETlhiWGIdpttg2rJ1oHsEiNUuYzj7d1MBKGhSMX4y8OpB9hhW6CjgajG-YVk3SU6JWaVBEY_1w49Q6U-KxD4nzMK5I85Cn1C1iDPExuOwuyRRH1XSxsXLQ9tURsLOytlp7LkUNvzxb5lxZ18ho-OkvkWVkS18oSxR5y__WllywD_6_NT64s"
So I should get a bearer token. How do I get it with say, curl?
I want standard web query such as using curl. I want to avoid unfamiliar library like some specialized oauth library.
I am making an app. I am not making a website. Should I even use oauth2?
I read about oauth2 here
https://aaronparecki.com/oauth-2-simplified/#roles
It says that "users" will see some website and they can "authorize".
Look. The user is me. I got the API key, secret, client id, client secret. I don't want "users" to be shown anything. I approve all this stuff.
Stex says that they will abandon their version 2 API and will use version 3API. They said that version 3 API uses Oauth.
Is oauth even suitable for an app that run unattended?

Related

Generating a JWT for Apple's DeviceCheck API

I'm attempting to use the DeviceCheck API from Apple. I can't seem to craft a request that doesn't fail with a 401 Unable to verify authorization token I've tried a handful of minor variations.
import java.security.KeyFactory
import java.security.spec.PKCS8EncodedKeySpec
import java.util.Base64
import io.jsonwebtoken.{Jwts, SignatureAlgorithm}
val deviceCheckPrivateKey = "<Key in plaintext without the key-guards>"
val privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder.decode(deviceCheckPrivateKey)))
val builder = Jwts
.builder()
.setHeaderParam("kid", "<key-id-from-file>")
.signWith(SignatureAlgorithm.ES256, privateKey)
.claim("iss", "<team-id>")
.claim("iat", System.currentTimeMillis())
println(builder.compact())
I take the output of this scratch file and plug it in here:
curl -i -H "Authorization: Bearer <Output>" -X POST --data-binary #ValidQueryRequest.json https://api.development.devicecheck.apple.com/v1/query_two_bits
as recommended by Apple's documentation.
Is the overall structure of this right? I'm trying to follow this tutorial which implies this structuring:
But this blurb from Apple:
Each request you send to the query and update endpoints must include an authorization header that contains your authentication key. The authentication key must must use the ES256 algorithm and be in the Base 64 URL–encoded JSON web token format. If your token doesn't use this format, you receive a BAD_AUTHENTICATION_TOKEN HTTP error.
Suggests that rather than signing using the key, my request should "contain my authentication key".
According to: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6
val builder = Jwts
.builder()
.setHeaderParam("kid", "<key-id-from-file>")
.signWith(SignatureAlgorithm.ES256, privateKey)
.claim("iss", "<team-id>")
.claim("iat", System.currentTimeMillis()) // <--- Should be seconds, not milliseconds

How to authenticate a Rails API with Google JWTs

On the frontend, using React and the Google Login Button, the user logs in to my application. Google returns the user's JWT to a callback URL on the frontend, encoded. I then deliver this JWT on each request to a Rails API and want the rails API to decode and verify this JWT, and if it is verified successfully, return the data that API endpoint is supposed to give.
I am currently using this code:
def google_public_key
x509 = OpenSSL::X509::Certificate.new ENV["GOOGLE_CERT"]
x509.public_key
end
The env var is described like this: https://gist.github.com/Connorelsea/c6b91a4b4b6889294fd4e2fcacb06564
I am getting this error: OpenSSL::X509::CertificateError (nested asn1 error)
If I do not verify, I can read the content of the JWT. From the JWT website it can be decoded, but not verified, as well.
Had the same problem and solved by setting the public_key as Pkey object not as a string in the constructor, try:
def google_public_key
x509 = OpenSSL::X509::Certificate.new
x509.public_key = OpenSSL::PKey::RSA.new ENV["GOOGLE_CERT"]
end

Authenticating to an API with a token

I'm working with the Zendesk API, an HTTPS-only, JSON API and authentication is required to update a resource, and the API supplies an API token to use when authenticating as different users. When updating a resource, I issue a PUT request over SSL, assign the appropriate JSON content to the request body, and specify the Content-Type request header as application/json.
Next, the API instructs its users to authenticate as the end-user by either using the user's email and password (which I can't do for several reasons) or to use the user's email address along with the API token. The following is my attempt to authorize to the API with the Authorization header:
#id = params[:id]
#comment_body = params[:comment]
uri = URI.parse "https://{subdomain}.zendesk.com/api/v2/requests/#{#id}.json"
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Put.new(uri.request_uri)
req.body = '{"request": {"comment":{"value":' + "\"#{#comment_body}\"" + '}}}'
req['Content-Type'] = 'application/json'
#The following two lines do not work!
credentials = Base64::encode64("{user_email}/token:{api_token}")
request.headers['Authorization'] = "Basic #{credentials}"
response = http.request(req)
The API specifies that the format for authentication using the API token is {user_email}/token:{api_token}. I encoded that format with Base64::encode64 and passed it to the Authorization Header preceded with Basic, but the response is a 401 Unauthorized. However, replacing those two lines with req.basic_auth {user_email}, {user_password} works fine.
So my question is, how can I authenticate as a different user using the email and the given API token as authentication instead of supplying the user's email and password to req.basic_auth?
The googling I've done on the topic has revealed very little; apparently it's a lot more common to use the normal {username}:{password} format when dealing with the Authorization header than an API token.
Thanks in advance!!
Update: Weirdly, trying to authenticate as the end-user with req['Authorization'] = "Basic #{credentials}" does not return a 401 Unauthorized Error or a WWW-Authenticate header while trying to authorize as request.headers['Authorize'] = "Basic #{credentials}" does.
Finally figured it out after much head-banging and nearly throwing my laptop out the window. Suddenly, the answer seems incredibly obvious.
When using Net::HTTP, its basic_auth method can also accept tokens depending on the API, and the Zendesk API specifies that the format for using the API token is {email}/token:{token}. Basic authentication uses the format {username}:{password}, where the two fields are separated by a colon, meaning in Zendesk's case I can place {email}/token as the first argument and {token} as the second argument (instead of the username as the first argument and the password as the second argument), so the following code is correct:
req.basic_auth "{email}/token", "{api_token}"
I hope anyone who found this useful could leave a comment. Nice to know I spared someone from this frustration.

What is the different between Dwolla API Key, Client_id & Client_Secret?

How to work with Dwolla API which required Client_id & Client_Secret
https://www.dwolla.com/oauth/rest/users/{account_identifier}?client_id={client_id}&client_secret={client_secret}
I already register Application. And Got Key and Secret
But when I call above described API Endpoint via Fiddler. Got bellow response.
{"Success":false,"Message":"Invalid application credentials.","Response":null}
Note: I tested Client_id = API Key / Client_id = Application Key. But the response remain same. What is the problem ?
The client_id is just another name for the API/Application Key, which identifies your application. The client/application secret is a string that functions as a password for your application. Just like a password, you should never give out your application secret; and if it's ever compromised, let us know immediately and we'll generate a new key/secret pair for you.
About your failed request: Try encoding your application key and secret. If special characters aren't escaped from the URL, the request will be interpreted differently from what you intend.
You can quickly encode the two strings from your Javascript console:
var key = "EUFH378&36%394749D\DWIHD";
encodeURIComponent(key);
Result: "EUFH378%2636%25394749DDWIHD"
var secret = "WOIDJ38&IDI\DK389DDDDD";
encodeURIComponent(secret);
Result: "WOIDJ38%26IDIDK389DDDDD"
And place their encoded equivalents back into your request URL:
https://www.dwolla.com/oauth/rest/users/gordon#dwolla.com?client_id=EUFH378%2636%25394749DDWIHD&client_secret=WOIDJ38%26IDIDK389DDDDD

Tridion UGC service and oAuth authentication

I've a problem when trying to do a webrequest to UGC and authenticate using oAuth. I'm making a webrequest such as:-
WebRequest wr = WebRequest.Create("http://ugc.service/odata.svc/Ratings(Id=200)");
wr.Headers["authorization"] = "OAuth " + auth;
Where auth is my token returned from the access_token.svc. According to the documentation the token returned from the service should be something like:-
HufXeuUt%2FYYElA8SYjJOkUkrXxV9dyXRirmKhjW%2Fb%2FU%3D
However, what I'm being returned from access_token.svc is more like:-
{"access_token":"client_id%3dtestuser%26expiresOn%3d1361898714646%26digest%3d%2fW%2fvyhQneZHrm1aGhwOlgLtA9xGWd77hkxWbjmindtM%3d","expires_in":300}
I've parsed the JSON to extract various strings and attempted to pass these through to the authorization but whatever I try I get an error in the logs - "ERROR OAuth2AccessToken - Digest is wrong." Exactly what part of the token and in what format should I be passing through to authorization?
Many thanks
John
Like you mentioned, the protocol is this:
You make a post request to the access token end-point to get a token (you need to provide here your client_id and your client_secret as headers or as query parameters);
You get an answer similar to this: {"access_token":"sometoken","expires_in":300};
2.1 Worth knowing is that the token is url encoded and in UTF-8 format so, on Java side you need to do URLDecoder.decode("sometoken", "UTF-8"); while on .NET side you need to do HttpUtility.UrlDecode("sometoken", System.Text.Encoding.UTF8);;
Your next request needs to include the authorization header. On Java side you do builder.header("authorization", "OAuth " + decodedTokenString); while on .NET side you can use Client.Headers["authorization"] = "OAuth " + DecodedTokenString;
Worth mentioning is that the SharedSecret defined in the cd_webservice_conf.xml (/Configuration/AuthenticationServer/SharedSecret/) of the TokenAccessPoint needs to be the same as the SharedSecret defined in the cd_ambient_conf.xml (/Configuration/Security/SharedSecret/) of the (WebService)EndPoint.
Are you sure you decoded properly the token gotten from the server? Are you sure that you configured the proper SharedSecret in the two configuration files?
Hope this helps.

Resources