Doorkeeper jwt with RS encryption - ruby-on-rails

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

Related

omniauth_openid_connect gem - Authentication failure! invalid_request: Rack::OAuth2::Client::Error, invalid_request :: Client credentials are invalid

Im using this gem to add Omniauth OpenID with a provider.
I configured the gem in the Devise Initializer, everything seems to be correct:
config.omniauth :openid_connect,
{
name: :openid_connect,
scope: %i[openid profile groups_rewardops scope_rewardops],
issuer: ConfigSettings.desjardins.issuer_url,
response_type: :code,
uid_field: 'sub',
response_mode: :query,
discovery: true,
send_scope_to_token_endpoint: false,
client_options:
{
port: 443,
scheme: "https",
host: ConfigSettings.desjardins.host,
authorization_endpoint: "/affwebservices/CASSO/oidc/rewardops/authorize",
token_endpoint: "/affwebservices/CASSO/oidc/rewardops/token",
userinfo_endpoint: "/affwebservices/CASSO/oidc/rewardops/userinfo",
identifier: ConfigSettings.desjardins.client_id,
secret: ConfigSettings.desjardins.client_secret,
redirect_uri: "#{ConfigSettings.api.base_url}front_end/users/auth/openid_connect/callback",
},
}
The flow I have atm is that the user can log in and grant access from the provider, then the provider sends a request to my devise callback url with the nonce, code and state. At this point everything seems to be correct but that request ends in failure when trying to generate the access_token with the following error:
ERROR -- omniauth: (openid_connect) Authentication failure! invalid_request: Rack::OAuth2::Client::Error, invalid_request :: Client credentials are invalid.
Im sure the identifier and the secret are correct, don't understand what's going on.
Since Im using discovery mode all the configs of the provider are in the .well-known you can check it here
Im blocked without ideas about how to debug the error. Checking at Rack::OAuth2 to see where the error is comming from I found this that says:
invalid_request: "The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed.",
It seems for some reason the access token request is malformed, but not sure what else apart of identifier and secret should I have in mind? I have seen many other examples of configuration and mine seems to be correct.
Since you are sure your credentials are correct, I suspect there is mismatch between the authentication method being used and the methods supported by the provider. Checking the .well-known config, I see this provider only supports client_secret_post. In your omniauth config, I see no options being passed to specify the authentication method. When I dive down into the code, I see that the underlying oauth2 gem defaults to using basic auth, which uses the indentifier and secret to construct an Authentication header. See: source code here
client_auth_method = args.first || options.delete(:client_auth_method).try(:to_sym) || :basic
case client_auth_method
when :basic
cred = Base64.strict_encode64 [
Util.www_form_url_encode(identifier),
Util.www_form_url_encode(secret)
].join(':')
headers.merge!(
'Authorization' => "Basic #{cred}"
)
In the client_secret_post authentication method, instead of providing client secret in the header, the client authorizes itself providing the secret in the HTTP request body as a form parameter. So this provider is not seeing your credentials. You could verify this by looking at the logs of the token endpoint request, which won't be visible in the browser, but rather from your rails BE to the the provider's server.
Try passing a client_auth_method in the client_options hash in your omniauth config. If you look at the case statement in the code I linked to above, there doesn't seem to be a named option for client_secret_post, but it is the default case. Any value for client_auth_method looks like it would work, but I would still use client_secret_post.

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.

JWT token security Check with Ruby

I am using ruby-jwt gem to generate token. I am not sure it's safe or not? How can I secure my payload. I tried different ways but still can hack payload.
> payload = {email: "gagangami#gmail.com", token: "xyz#123"}
# Way1
> token1 = JWT.encode(payload, Rails.application.secrets.secret_key_base, 'HS256')
#=> "eyJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImdhZ2FuZ2FtaUBnbWFpbC5jb20iLCJ0b2tlbiI6Inh5ekAxMjMifQ.l42W9P4lyP2XWXytu8qpasc6mAFg01Dg57Az1bfxgS8"
# Way 2
> rsa_private = OpenSSL::PKey::RSA.generate 2048
> rsa_public = rsa_private.public_key
> token2 = JWT.encode payload, rsa_private, 'RS256'
=> "eyJhbGciOiJSUzI1NiJ9.eyJlbWFpbCI6ImdhZ2FuZ2FtaUBnbWFpbC5jb20iLCJ0b2tlbiI6Inh5ekAxMjMifQ.U6DO9f9KZ_-GVhviACpXmuyc0dQUznPxZdCaaspr5JP36EweAuP8Wn_R2jvK2ahW0BR-RAh7Z9ChyIk94tDjasSbUYdoW_re299RB-ZmS0NVpCEa-g20sT-5JKCTwbD25vXYdxM4E0swQ81sKw35H5T8ZXSHsrE4bP5mA-me_Wli3hyGacb5O3esStPMdRC5r20qCoK7QW7Wl7NnZHLYjIn8k7lxsFmheNyl1l3OSLY92bxGkSyx4lom6bWqEMXSFdLWqPdKTOX9RZbNVi_6fGms79W6XXnb29htqkM1Z1h0RLXzjCODbALpa7At88xWr32IkHzwNxRJ28VAOJB3Qw"
If I try to decode JWT token manually without secret it gives error. works fine.
But If I paste above token token1 and token2 at https://jwt.io/ I am able to see payload. Is this safe way or Bug? for reference I am attaching two screenshots.
JWT is not for encryption, but for identification.
The JWT generator signed the payload with a private key, you can verify if it is generated by the specific generator or not, using a public key. But the payload is not encrypted, anyone can read it.
For example. John sends you a message that "he is at home.", and signed it by his private key. Everyone can read this message but you can verify it is really sent by John, not someone else like Alice.
Anyone can decode, but only those who have your secret can verify the token.
It is important to understand that the purpose of using JWT is NOT to hide or obscure data in any way. The reason why JWT are used is to prove that the sent data was actually created by an authentic source.
https://medium.com/vandium-software/5-easy-steps-to-understanding-json-web-tokens-jwt-1164c0adfcec

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

get an access code from the doorkeeper gem

when we request by click on authorize.........
request send to the
http://localhost:3000/oauth/authorize?client_id=57070f3927deea2d38c50afa042ae0o9u0c539e4d45a79e203cd66d286f9ec8e&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2F&response_type=code
the response come
http://localhost:3000/?code=1560b332321dd2obc99ed3411c78614ce0d59c90e9264c87b7f2f179441d6b4e
now i hve to copy the "code" put in console like below code.....
app_id = "57070f3927deea2d38c50afa042ae0o9u0c539e4d45a79e203cd66d286f9ec8e"
secret = "1dbd541132ca2bdeb9fe83b41d24490b2be445c30fd1856e5914f6d343c4a71b"
client = OAuth2::Client.new(app_id, secret, site: "http://localhost:3000/")
client.auth_code.authorize_url(redirect_uri: callback)
access = client.auth_code.get_token('1560b332321dd2obc99ed3411c78614ce0d59c90e9264c87b7f2f179441d6b4e', redirect_uri: callback)
access.token
this how the access_token is generated...
is there a better way to get the access code from the dookeeper
This is standard way described by oauth2.0 specification for autorization code based retrieval of access token. There are other ways like implicit, password and client credentials. Check out the details in RFC and try it with Doorkeeper.

Resources