How to set SameSite to none in Rails 6 API with CreateReactApp? - heroku

I have a Rails 6 app acting as an API for a frontend app originally created with create-react-app. I am trying to store a session token to preserve login on page refresh.
When running locally, Chrome shows that SameSite=Lax but the session token is stored anyway. On the live site, SameSite is still Lax, but Chrome gives a little warning saying that the Set-Cookie header was blocked because it came from cross-site response. Both the frontend and api are deployed on Heroku in separate repos.
I've tried a number of things:
secure_headers gem, with the following in app/config/initializers/secure_headers.rb:
SecureHeaders::Configuration.default do |config|
config.cookies = {
secure: true, # mark all cookies as "Secure"
httponly: true, # mark all cookies as "HttpOnly"
samesite: {
lax: false
}
}
end
I have the following in app/config/initializers/session_store.rb:
Rails.application.config.session_store :cookie_store, :key => '_session_id',
:domain => :all,
:same_site => :none,
:secure => :true,
:tld_length => 3
I've tried cookie_serializer, although I commented everything out of that file.
I have the rack-cors gem, with the following in the cors.rb initializer:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'http://localhost:8080', 'http://localhost:5000', 'https://frontend-auth-frontend.herokuapp.com'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
credentials: true,
exposedHeaders: ["Set-Cookie"]
end
end
I've tried a few other gems I saw recommended on SO but I don't remember all of them.
So... yea, how do I set SameSite so that my heroku frontend (react) can store cookies from the heroku api (rails 6)?
I can provide other info about the project, specific versions, etc., just not sure what else would be helpful.
Thanks!

the following code should set sameSite to none (the key is in the last line)
//config/application.rb
config.api_only = true
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore,
key: '_cookie_name', path: '/', same_site: :None, secure: true

Related

OctoKit Ruby Authentication

I'm sure that this is a simple error, but I'm interested in writing a program that collects information on all of my github repositories. While this seems simple enough to do with Octokit, I've run into issues associated with authenticating my session.
client = Octokit::Client.new \
:login => 'MY_USER_NAME',
:password => 'MY_PASSWORD'
puts client
user = client.user("MY_USER_NAME", :headers => { "PERSONAL_ACCESS_TOKEN_NAME" => "TOKEN" })
puts user
Unfortunately this results in the following:
GET https://api.github.com/users/mccoleman75225: 401 - Must specify two-factor authentication OTP code. // See: https://developer.github.com/v3/auth#working-with-two-factor-authentication (Octokit::OneTimePasswordRequired)
How does someone go about authenticating their session?
As of January 2022, you can create a PAT (Personal Access Token) in your GitHub Developer Settings and use that to connect through the Octokit client like so:
client = Octokit::Client.new(:access_token => "<Your Personal Access Token>")
user = client.user
user.login
# => "monacat"
Here's a step-by-step guide on how to create a PAT. Try to select the correct permissions when creating your token or you'll get back a 403 error with a message explaining the missing scope. You can always go back and edit your scopes later though.
Sources:
Octokit.rb — Authentication
GitHub API Authentication - Personal Access Tokens
Looks like you have 2 Factor Authentication enabled on your account so you'll need to add your 2FA token:
client = Octokit::Client.new \
:login => 'defunkt',
:password => 'c0d3b4ssssss!'
client.create_authorization(:scopes => ["user"], :note => "Name of token",
:headers => { "X-GitHub-OTP" => "<your 2FA token>" })
# => <your new oauth token>
See documentation

How to authenticate oauth, Magento 2.0 SOAP in Ruby

Having a problem authenticating to Magento 2 SOAP with oauth credentials.
For a magento 1.9 version this is very straightforward:
client = Savon.client(
wsdl: "https://example.com/api/soap/?wsdl=1",
log: true,
pretty_print_xml: true
)
session_id = client.call(:login, message: { username: "username", apiKey: "key" })body[:login_response][:login_return]
client.call(:call, message:{resource_path: 'catalog_product.list', session_id: session_id}).body
Works as expected. With oauth it gets bit more complicated.
I tried all kind of different things, like:
client = Savon.client(
wsdl: "http://example.com/index.php/soap/default?wsdl_list=1",
soap_header: { 'Authorization:' => "Basic xxxx"},
pretty_print_xml: true
)
client.call(:call, message:{resource_path: 'catalogProductAttributeGroupRepositoryV1'}).body
Hope somebody already made an oauth-magento 2 soap integration and give me some pointers.
You need to create a new integration from admin to get authentication keys. These links will be useful resource:
https://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html
https://gist.github.com/rafaelstz/ecab668b80fece4d9acdb9c5358b3173

Mailgun::CommunicationError via nginx '301 Moved Permanently' error

I have a Ruby web app that sends email via Mailgun.
My Mailgun account & gem are properly set up and I can send emails manually (via curl, for instance).
The API key and the API base URL (https sandbox domain) are stored in environment variables.
When I attempt to send emails from the app like this:
def initialize(mailer: nil)
#mailer = mailer || Mailgun::Client.new(ENV['MAILGUN_API_KEY'])
end
then:
def call(user)
mailer.send_message(ENV['MAILGUN_SANDBOX'], {from: '...',
to: user.email,
subject: '...',
text: "..."})
end
When I run the app with Sinatra via localhost:xxxx, I get a Mailgun::CommunicationError at /.../... 301 Moved Permanently: ... nginx pointing to this line:
mailer.send_message(ENV['MAILGUN_SANDBOX'], ...
Any idea why that happens? I've researched the issue for hours but couldn't find a clue on what to do next.
Thanks!
I ran into this same issue. If you have already fixed this then hopefully this can help someone else.
I switched over to message builder for ease of use and being able to render my html but I'm pretty sure it will still send with the format you have setup with :text
When I switched over to the proper domain in the .env file I believe it solved my issue. You'll need 2 different domains to use Mailgun. The first is the full domain for your sandbox. ENV['MAILGUN_DOMAIN'] it is the sandbox domain with the full https://api.mailgun.net/v3/sandboxXXXXxxxXXXXXX.mailgun.org to send most of the mail formats.
You'll also need the last half of the full domain to send messages. That's just the sandboxXXXXxxxXXXXXX.mailgun.org which is passed into the MessageBuilder or other message .send_message method. When I had them mixed up or both the same I kept on getting this error. When I switched over to separate the two in my development.rb and some_mailer.rb is when I could send the mail without a problem.
Below is my file setup, for reference. I'm pretty new to all of this but this is how I'm setup and it's working for me so hopefully it helps.
# .env
MAILGUN_DOMAIN='https://api.mailgun.net/v3/sandboxXXXXxxxXXXXXX.mailgun.org'
MAILGUN_SEND_DOMAIN='sandboxXXXXxxxXXXXXX.mailgun.org'
# development.rb
ActionMailer::Base.smtp_settings = {
:authentication => :plain,
:address => "smtp.mailgun.org",
:port => 587,
:domain => "ENV['MAILGUN_DOMAIN']",
:user_name => "ENV['MAILGUN_USERNAME']",
:password => "ENV['MAILGUN_PASSWORD']"
}
# some_mailer.rb
def some_mail_notification(user)
#user = user
mg_client = Mailgun::Client.new ENV['MAILGUN_KEY']
mb_obj = Mailgun::MessageBuilder.new
mb_obj.from "email#testing.com", {'first' => 'Customer', 'last' => 'Support'}
mb_obj.add_recipient :to, #user.email, { 'first' => #user.first_name, 'last' => #user.last_name }
mb_obj.subject "Your Recent Purchase on Some Site"
mb_obj.body_html ("#{render 'some_mail_notification.html.erb'}")
mg_client.send_message("sandboxXXXXxxxXXXXXX.mailgun.org", mb_obj)
end
I left the send_message above to the sandbox domain but you can set that as an environment variable in the .env file.

How to set a cookie in Sinatra

I am developing a web application using Sinatra and Ruby. I need to set a cookie that is accessible from all subdomains. My original code was this:
#language = 'en-US'
cookies[:USER_LANGUAGE] = #language
This produced the desired effect (e.g. setting the cookie "USER_LANGUAGE" equal to "en-US"
However, it was not accessible from all subdomains. After looking at How to set a cookie on a separate domain in Rails and other similar questions, I have tried this:
#language = 'en-US'
cookies[:USER_LANGUAGE] = {
:value => #language,
:domain => '.example.com'
}
When I check the cookie data, it is set completely wrong. The value of the cookie is everything inside the brackets, and the domain is still only example.com (not .example.com)
Here is the value produced:
%7B%3Avalue%3D%3E%22en-US%22%2C+%3Adomain%3D%3E%22.example.com%22%7D
If you want all your cookies to be accessible from all subdomains, you can set the cookie options for your application:
set :cookie_options, :domain => '.example.com'
If just need it on one cookie, you can do this (instead of using the cookies object):
response.set_cookie(:USER_LANGUAGE, :value => #language, :domain => '.example.com')

RestClient.get returning certificate verify failed

I am trying hit an internal testing API server using RestClient and Ruby v. 2.2.1.
This is essentially the code:
url = "https://10.10.0.10/thing/i/want/to/get"
header = {
:content_type => "application/json",
:"x-auth-token" => "testingtoken"
}
response = RestClient.get url, header
This is the failure message I get:
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (RestClient::SSLCertificateNotVerified)
If I'm reading this right, it looks like Ruby couldn't accept the SSL security certificate. This call works in the Chrome app Postman, but in order for it to work, I have to hit the URL in Chrome itself and accept that the connection is not secure (but proceed anyway), and THEN it will work in postman.
Is there a way to ignore the certificate failures and proceed anyway in Ruby?
Try using #execute(&block) with verify_ssl set to false.
:verify_ssl enable ssl verification, possible values are constants
from OpenSSL::SSL::VERIFY_*, defaults to OpenSSL::SSL::VERIFY_PEER
url = "https://10.10.0.10/thing/i/want/to/get"
headers = {
:content_type => "application/json",
:"x-auth-token" => "testingtoken"
}
RestClient::Request.execute(
:url => url,
:method => :get,
:headers => headers,
:verify_ssl => false
)
see: http://www.rubydoc.info/github/rest-client/rest-client/RestClient/Request#execute-instance_method
RVM
Additional solution for RVM users from: https://toadle.me/2015/04/16/fixing-failing-ssl-verification-with-rvm.html
This discussion on Github finally gave the solution: Somehow RVM comes
with a precompiled version of ruby that is statically linked against
an openssl that looks into /etc/openssl for it's certificates.
What you wanna do is NOT TO USE any of the precompiled rubies and
rather have ruby compiled on your local machine, like so:
rvm install 2.2.0 --disable-binary
rest-client verify certificates using the system's CA store on all platforms by default. But is possible set to false the option :verify_ssl or specify :ssl_ca_file or :ssl_ca_path or :ssl_cert_store to customize the certificate authorities accepted.
See documentation
So you could simply set :verify_ssl to false:
url = "https://10.10.0.10/thing/i/want/to/get"
header = {
:content_type => "application/json",
:"x-auth-token" => "testingtoken"
}
resource = RestClient::Resource.new(
url,
headers: header,
verify_ssl: false
)
response = resource.get
You could try immediately with a host which use a self-signed certificated provided by https://badssl.com/. Simply copy the snippet below in your irb console.
response = RestClient::Resource.new(
'https://self-signed.badssl.com/',
:verify_ssl => false
).get

Resources