How to authenticate a Rails API with Google JWTs - ruby-on-rails

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

Related

JWT gem - retrieve public signing key from remote authority URI

I have:
An OpenID Connect identity / token server written in AspNet 6
A resource API that I want to protect with access tokens from the identity server, writen in Ruby / Rails
The issued tokens are assymetrically (public/private key) signed JWTs.
If I was writing the resource API in .Net, I would provide a URI for the token authority when setting up authentication, e.g.
app.UseJwtBearerAuthentication(new JwtBearerOptions() {
Authority = "https://uri.to.my.identity.server"
}
The JWT bearer authentication middleware would use this URI to find and retrieve the public key from the identity server, so that it can be used to validate token signatures.
I am looking for a similar approach when using the Ruby JWT gem (https://github.com/jwt/ruby-jwt)
The RSA example on that site just provides the public key explicitly, e.g.
rsa_private = OpenSSL::PKey::RSA.generate 2048
rsa_public = rsa_private.public_key
decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' }
I could call the identity server discovery endpoint directly, but I was hoping there might be something part of the library (or another library) that would help with this.

Doorkeeper jwt with RS encryption

I am using Doorkeeper for authorization and JWT to generate access token in my application. And enabled below option like
secret_key_path location to my private.pem file
encryption_method is RS256
use_application_secret false
using Doodkeeper::JWT configure block. Issue I am facing is once request hit for token generation in backend it prompts for Enter PEM pass phrase:
and not getting any response back because its waiting Pass phrase to enter once you provided phrase then you will get access token as response.
Note : I generate private.pem file for encryptions and using in JWT to generate access_token using private.pem.
Issue the secret is not passed to OpenSSL so I modified as below by
reopened the JWT module and added to monkey patch
module JWT
class << self
def rsa_key_file
secret_key_file_open {|f| OpenSSL::PKey::RSA.new(f, Doorkeeper::JWT.configuration.secret_key)}
end
end
end

How should I use webclient for 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?

Unable to validate access token signature obtained from Azure AD in order to secure Web API

I am trying to secure my web api (.net core 2.2) with Azure Ad using implicit flow.
I registered my application in Azure AD using the Azure Portal > Azure Active Directoy > App Registrations > New Application Registration:
Name = MyWebApi
Application Type = Web app / API
Sign-on URL = http://localhost:55000
Once this app is created, I opened its Manifest file and changed oauth2AllowImplicitFlow from false to true.
Thats all I did for the app registration in azure portal.
Then I called the following URL manually from my chrome browser to get access_token:
https://login.microsoftonline.com/MY-AD-TENANT-GUID/oauth2/v2.0/authorize?client_id=MY-REGISTERED-APP-GUID&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A55000&scope=openid&response_mode=fragment
the response from calling the above url is:
http://localhost:55000/#access_token=MY-ACCESS-TOKEN&token_type=Bearer&expires_in=3600&scope=profile+openid+email+00000003-0000-0000-c000-000000000000%2fUser.Read&session_state=b2be972a-cfbc-49f1-bfc0-6c93f6c87d02
when I pass MY-ACCESS-TOKEN as Bearer token in Authorization header to my Web API (.net core 2.2) I get the following exception:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: N-lC0n-9DALqwhuHYnHQ63GeCXc'.
I then tried manually verifying the signature:
when I paste MY-ACCESS-TOKEN in https://jwt.io/ the header is:
{
"typ": "JWT",
"nonce": "AQABAAAAAACEfexXxjamQb3OeGQ4Gugvm6YdOT-bkA0IPllKMt06-J8If5AQ075TVCav94X_ZYcEYKaPneqdJcqYry-Z4XjX0eMN_fiJX_8wXe9D2b6eRiAA",
"alg": "RS256",
"x5t": "N-lC0n-9DALqwhuHYnHQ63GeCXc",
"kid": "N-lC0n-9DALqwhuHYnHQ63GeCXc"
}
I then went to this URL to obtain the public key for kid: N-lC0n-9DALqwhuHYnHQ63GeCXc
https://login.microsoftonline.com/common/discovery/keys
I then pasted the following as a public key on jwt.io to validated token signature:
-----BEGIN CERTIFICATE-----
OBTAINED-PUBLIC-KEY-FROM-THE-ABOVE-URL-HERE
-----END CERTIFICATE-----
and I again get Invalid Signature.
I have been to this thread: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609, but I am not sure why does my token header has nonce value or if this is an issue at all in my case or not.
Any ideas what I am doing wrong here?
I tried this on my side, it worked well.
Request url:
https://login.microsoftonline.com/tenant-name/oauth2/v2.0/authorize?client_id=application_id&response_type=token&redirect_uri=https://snv2app.azurewebsites.net&scope=api://f3d966c0-517e-4e13-a5bb-9777a916b1a0/User.read openid&response_mode=fragment
And when I got the access_token, I parsed it in the jwt.io and entered the public key, I got the result:
What is happening here is the token you are receiving is an access_token for the userInfo endpoint. The audience is graph. Tokens for graph have been modified in a special way so that they must be transformed before the signature can be validated. This allows for graph to forward the token downstream (after transforming) and not worry about a forwarding attack to occur.
To validate see if 'aud == graph'.

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

Resources