Rails/ Heroku: Setting up code to read variables at run time - ruby-on-rails

I made a website that uses the Twitter Ruby gem. On local host, I can get the Twitter gem to work fine, but when I deployed it to Heroku, I'm having trouble signing in via Twitter.
Heroku provides instructions (using Amazon S3 variables) about adding the CONSUMER_KEY and the CONSUMER SECRET
$ cd myapp
$ heroku config:add S3_KEY=some_key_here S3_SECRET=some_secret_here
I did that.
Then when I go to test sign in, I get this in the url. This url is the same as when (on a local host) I forget to add CONSUMER_KEY etc, so I'm thinking that I didn't set up the CONSUMER_KEY and CONSUMER_SECRET properly on Heroku...
Heroku provides further details about setting up a file in config/initalizers to read the variables at runtime, but I think the Github project I forked and then adapted already has this set up https://github.com/sferik/sign-in-with-twitter/blob/master/config/initializers/omniauth.rb so I'm not sure what's going on.
Set up your code to read the vars at runtime in config/initializers/s3.rb:
AWS::S3::Base.establish_connection!(
:access_key_id => ENV['S3_KEY'],
:secret_access_key => ENV['S3_SECRET']
)
UPDATE
error message in Heroku logs when I try to signin via Twitter. Note, i can sign in via local host.
2012-01-02T20:01:43+00:00 app[web.1]:
2012-01-02T20:01:43+00:00 app[web.1]: Started GET "/auth/twitter?utf8=%E2%9C%93" for 64.46.7.250 at 2012-01-02 20:01:43 +0000
2012-01-02T20:01:44+00:00 app[web.1]:
2012-01-02T20:01:44+00:00 app[web.1]: OAuth::Unauthorized (401 Unauthorized):
2012-01-02T20:01:44+00:00 app[web.1]:

This could be one of two things.
Either your keys are not setup correctly, or the route that the Twitter OAuth callback comes back to is not correct (in that it is not processing correctly).
The easiest to check is your Heroku config:
heroku config --app your_app_name
This should show CONSUMER_KEY and CONSUMER_SECRET (I'm assuming your use of S3_KEY and S3_SECRET above are placeholders)
Should this config be correct, and it still doesn't work you'll need to dig into the processing of the request that comes back to your application. It seems to be processing /auth/twitter as it should, but something it not correct within this step.

Related

Devise Google Omniauth working in Local, but not in Production

Google OAuth2 on Production is not working for me. This is with the Devise gem.
The log shows this all the time on Production. (Removed Prefixed output from server)
Started POST "/users/auth/google_oauth2" for 112.205.146.56 at 2023-01-27 01:14:38 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "commit.x"=>"25", "commit.y"=>"16"}
Redirected to https://automateton.com/users/sign_in
But it works on Local!!!
Started POST "/users/auth/google_oauth2" for ::1 at 2023-01-27 09:20:01 +0800
DEBUG -- omniauth: (google_oauth2) Request phase initiated.
The .rbenv-vars should work in Production as I've put the secret and master key there. I've also put my DB creds and Google creds there.
Gemfile includes
gem 'devise
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection'
Localhost omniauth includes
localhost:3000/users/auth/google_oauth2/callback # Redirect URI in Google Developer Console
Can you help me with this? Thank you very much!
I've also tried the following:
Added SSL certification with Let's Encrypt
Added callback to my www.example.com/users/auth/google_oauth2/callback (redacted domain name)
Changed Google Oauth from test mode to production mode.
EDIT: I tried switching to Sorcery Gem and realized that the problem still persists. I think it's the CSRF problem that was already present in the other questions. However, I've tried the solutions already and they don't work.
e.g. if I use the skip_verify_token (non-verbatim) action or the protect_from_forgery prepend: true. It still doesn't work as the user is still not logged in (for both Sorcery and Devise). I still get sent back to the sign in page.
So, I went back to Devise to get a higher possibility stack overflow answers.
This is a bit of a facepalm moment for me. I've apparently set my config/initializers/session_store.rb to sample.com for the domain. So both OmniAuth for google and actual users/sign_in isn't working.
My settings before
domain = Rails.env.development? ? 'localhost' : 'sample.com'
AppName::Application.config.session_store :cookie_store, key: '_app_session', domain:
domain = Rails.env.development? ? 'localhost' : 'appname.com' # appname redacted but I changed it to the actual host name
AppName::Application.config.session_store :cookie_store, key: '_app_session', domain: (ruby 3.1.0, domain: domain shortcut)
Now it works!

Rails credential values are nil while running tests on github actions

I am encoding and decoding JSON web tokens using Rails secret_key_base, my secret_key_base is in the credentials.yml.enc file. In one of the test, I am using this function to decode JWT,locally the tests are running fine but on github action it is failing, I found out the the value of Rails.application.crendentials.secret_key_base is nil when running the test on github action. I fixed those tests by mocking like this
allow(Rails.application.credentials).to receive(:secret_key_base).
and_return("secret")
Is there a way I don't have to do this on github action for other credentials. Also since the master.key was not committed I hoped that I would see this error
ActiveSupport::MessageEncryptor::InvalidMessage
while reading from the credentials file but that also didn't happen.
This is a link to my project if that clears things up.
In Rails 6, you can create credentials.yml.enc file per environment.
In vscode:
EDITOR="code --wait" rails credentials:edit --environment production
EDITOR="code --wait" rails credentials:edit --environment test
it gives you production.key, production.yml.enc, test.key, test.yml.enc.
You can then commit test.key to github for testing or even better, set this key in RAILS_TEST_KEY env.
Though it gets a little bit tricky to maintain both env files. You can create credenetials.yml.example file with empty envs for reference
I think 'the cleanest/right way' to do this is to add master key(value from config/master.key) into github secrets.
Go to repository settings->secrets(left side menu)->new repository secret.
It makes sense to name it RAILS_MASTER_KEY.
And then in your workflow file add
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
And that's it, Rails will be smart enough to use that variable in credentials decryption.
No need to make additional credentials files. For me it's working with only one credentials.yml.enc
EDIT: Even better, if you can skip using credentials, add heroku config variable SECRET_KEY_BASE and in config/application.rb add
config.secret_key_base = ENV['SECRET_KEY_BASE']
and for production use Rails.configuration.secret_key_base,
for test/development Rails.application.secrest.secret_key_base that's set by rails
ex.
SECRET_KEY = Rails.env.production? ? Rails.configuration.secret_key_base : Rails.application.secrets.secret_key_base
This way you don't have to store master key on every machine that's running your app. ex. coworkers, github actions, staging, production.

Force Rails Paypal gem to use Sandbox instead of Live

A short story: I installed a development server on Heroku that is running in production mode.
I am not very familiar to the paypal-sdk-rest gem that is installed in this app (actually I'm new to RoR).
Reading the documentation here https://github.com/paypal/PayPal-Ruby-SDK I found out that there is a config yml file (config/paypal.yml) with the client_id and the client_secret for both Sandbox and Live for development and production environments. And a reference it to in config/initializers/paypal.rb.
When I'm working on localhost I can create payments on Sandbox and when I'm on my AWS server I can create payments on Live. But on Heroku I need it to create payments on Sandbox and not on Live. So I commented the reference to paypal.yml in paypal.rb and stated this in paypal.rb:
#this was added
PayPal::SDK.configure({
:mode => "sandbox",
:client_id => "my-sandbox-id",
:client_secret => "my-sandbox-secret"
})
Before sending files to Heroku I'm testing on localhost and I was expecting to see the sandbox payment page since it was working before removing the configuration file. I'm getting this message error instead:
{"name"=>"BUSINESS_VALIDATION_ERROR",
"details"=>[{"field"=>"validation_error", "issue"=>"Incorrect Template
Id."}], "message"=>"Validation Error.",
"information_link"=>"https://developer.paypal.com/webapps/developer/docs/api/#BUSINESS_VALIDATION_ERROR",
"debug_id"=>"some id here"}
Additional information: before removing the configuration file I was just copying the development info to production. I was testing on Heroku and getting the same error.
Any ideas folks?
I would add the keys via an environment variable. That way each environment will reference the correct key and you don't have to check them into source control. https://github.com/laserlemon/figaro is a good gem if you want to go that route. Alternatively you can set up your config/paypal.yml file to reference the different environments. That would look more like:
development:
:mode: "sandbox"
:client_id: "my-sandbox-id"
production:
:mode: "not-sandbox-er-whatever"
:client_id: "my-not-sandbox-id"

hardcoding CONSUMER_KEY and CONSUMER_SECRET

https://github.com/ryanatwork/sign-in-with-linkedin
This example rails application that lets a user log in with LinkedIn requires that the "rails server" command in the terminal be prefaced by 'CONSUMER_KEY=[consumer key] CONSUMER_SECRET=[consumer secret]' so that the whole command looks like:
CONSUMER_KEY=[consumer key] CONSUMER_SECRET=[consumer secret] rails server
The linkedin login obviously won't work with a consumer key/secret, but I'm having trouble hardcoding my consumer key/secret into the app so that I can deploy to Heroku successfully, but am not having any luck. I've tried in several different config and controller files without any luck. Help appreciated!
When you deploy to Heroku you need to have these variables set using the heroku config command:
heroku config:add CONSUMER_KEY=[consumer key]
If you use Foreman to start your server (as Heroku does at their end) then you can have these variables loaded from a local file which never gets committed into your source control (you don't want these secret details in your source control)
Don't hardcode to heroku. You can use environment variables in Heroku to set CONSUMER_KEY and CONSUMER_SECRET.
Here are the docs from Heroku:
https://devcenter.heroku.com/articles/config-vars

How do I add domains to Heroku app using Ruby code?

I'm creating an app that allows users to use their own domain. What method do I use in my Rails app to automatically register their chosen domain with Heroku? I'll also need to deregister it if they change it.
I have contacted Heroku for the same thing, and they just pointed me at their api, and said it is fine to use it that way.
I'm afraid there isn't. Our API is "documented" only by the code of the client.
You may find our google group helpful for getting advice from community members as well: http://groups.google.com/group/heroku/
Oren
Here's the simple how-to:
require 'heroku'
heroku = Heroku::Client.new('heroku_username', 'heroku_password')
heroku.add_domain('heroku_app_name', 'example.com')
heroku.remove_domain('heroku_app_name','example.com')
See the api for more.
Of course I'd recommend against putting a plaintext password into your code. A nice thing you can do is use the heroku environment variables to get your passwords out of the code.
heroku = Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASSWORD'])
and then you can set the environment variables on your app with
$> heroku config:add HEROKU_USER='heroku_username'
$> heroku config:add HEROKU_PASSWORD='heroku_password'
from the command line.
The heroku gem has now been deprecated. You should use the heroku.rb gem instead. The commands have changed slightly, but it's essentially the same.
require 'heroku-api'
heroku = Heroku::API.new(:api_key => API_KEY) # use API Key
heroku = Heroku::API.new(:username => USERNAME, :password => PASSWORD) # use username and password
heroku = Heroku::API.new(:headers => {'User-Agent' => 'custom'}) # use custom header
heroku.delete_domain('app', 'example.com') # remove the 'example.com' domain from the 'app' app
heroku.get_domains('app') # list configured domains for the 'app' app
heroku.post_domain('app', 'example.com') # add 'example.com' domain to the 'app' app
The way you usually add domains in Heroku is using the Heroku API through the Heroku gem.
There's a command called heroku domains:add you can invoke
$ heroku domains:add example.com
As I said before, the client calls the Heroku API. You can extract the Heroku Domain API information from the library and create a custom script that calls the Heroku API to add and remove a domain from your app.
Here's the client source code.
Note. Because you are "reverse engineering" and API which appears to be not documented, you should ask Heroku permission to do that, just to be sure you are not creating something against their TOS.
The gem is from heroku and is the recommended approach. I just contacted Heroku with the same question and this was there response:
You need to tell Heroku about the domain and where to route it as well. The CNAME tells DNS how to get the request to Heroku. Now you must tell Heroku which app to send it to. You do this by adding the domain to your app. In your case you would need to run "heroku domains:add my.domain.com" to your app. You can also do this programmatically from inside your application over our API. See the Heroku gem (http://github.com/heroku/heroku) for an example of how to connect and use the API.

Resources