Google Oauth2 Client ID not found in Rails - ruby-on-rails

I'm trying to connect to the Google Calendar API using rails, but it keeps telling me Missing required parameter: client_id Can anyone tell me what i'm doing wrong?
Code:
omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_SECRET_KEY'],
{
scope: 'https://www.googleapis.com/auth/calendar, hidden#gmail.com'
}
end
secrets.yml
development:
secret_key_base: xxxxxxxxx
GOOGLE_CLIENT_ID: xxxxxxx
GOOGLE_SECRET_KEY: xxxxx
test:
secret_key_base: xxxxxxx
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
development.rb
GOOGLE_CLIENT_ID = Rails.application.secrets.GOOGLE_CLIENT_ID
GOOGLE_SECRET_KEY = Rails.application.secrets.GOOGLE_SECRET_KEY
I also have a client_secrets.json file that has the downloaded code from Google.

As others have noted, I'd advise you to regenerated new secrets: everyone can still see your keys using the edit option in SO.
But to answer your question, there is no need to do some kind of passing through using globals, you can simply access your secrets in the omniauth initializer (config/initializers/omniauth.rb):
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, Rails.application.secrets.GOOGLE_CLIENT_ID, Rails.application.secrets.GOOGLE_SECRET_KEY
end
I hope your indent in the config/secrets.yml file is by accident, development: should be on a tab/double space before its values:
development:
secret_key_base: xxxxxxxxx
GOOGLE_CLIENT_ID: xxxxxxx
GOOGLE_SECRET_KEY: xxxxx
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
GOOGLE_CLIENT_ID: <%= ENV["GOOGLE_CLIENT_ID"] %>
GOOGLE_SECRET_KEY: <%= ENV["GOOGLE_SECRET_KEY"] %>
Personally I like my YAML keys to be lowercased, but I guess that is just something of a personal preference.

Related

What's the correct way of defining secret_key_base on Rails 6?

What's the correct way of defining secret_key_base on Rails 6 now that we have per-environment credentials?
My environment has the variable SECRET_KEY_BASE but Rails is not picking it up. I tried defining secret_key_base in config\credentials\production.yml.enc but it has no effect on Rails.application.credentials.secret_key_base
I know config/secrets.yml with
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
works, but, is that the Rails 6 way?
The right way to access and check for secret_key_base in Rails 6 is no longer:~
Rails.application.credentials.secret_key_base
it now is:
Rails.application.secret_key_base
I'm not sure if this is Rails 6 or it's been like this forever. This becomes pretty clear when looking at this method, and its implementation:
https://github.com/rails/rails/blob/09a2979f75c51afb797dd60261a8930f84144af8/railties/lib/rails/application.rb#L410-L427
# The secret_key_base is used as the input secret to the application's key generator, which in turn
# is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies.
#
# In development and test, this is randomly generated and stored in a
# temporary file in <tt>tmp/development_secret.txt</tt>.
#
# In all other environments, we look for it first in ENV["SECRET_KEY_BASE"],
# then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
# the correct place to store it is in the encrypted credentials file.
def secret_key_base
if Rails.env.development? || Rails.env.test?
secrets.secret_key_base ||= generate_development_secret
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
Both development and test mode have their own way of generating and storing the secret key base. For everything else, it pics it up from the environment, or credentials or secrets, in that order.
Docker users in development might consider this in their entrypoint.sh:
if [ "$RAILS_ENV" = "development" ]; then
printf $SECRET_KEY_BASE > ./tmp/development_secret.txt
fi
I've tried to solve that problem few days ago.
And what I learned:
First attempt
I try to use credentials per environment with
$ EDITOR=nano rails credentials:edit --environment development
$ EDITOR=nano rails credentials:edit --environment staging
$ EDITOR=nano rails credentials:edit --environment production
My creds files and keys were placed in config/credentials.
I set necessary variables straight there. It's usable solution, but we met a problem with our deployment at Kubernetes cluster, when our devopses wants to use helm configs. So, predefined credentials is not applicable for that case.
Second attempt
After that I've tried to use ENV-variables in my credentials files.
Unfortunately, it's not works too:
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
Final attempt
Finally, I did graceful degradation to gem config with default configuration, when you per-environment settings placed there:
config/settings.yml
config/settings/development.yml
config/settings/production.yml
config/settings/test.yml
And my settings.yml file consists only ENV-variables, like so:
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
db:
host: <%= ENV['DB_HOST'] %>
port: <%= ENV['DB_PORT'] %>
pool: <%= ENV['DB_POOL'] %>
user: <%= ENV['DB_USER'] %>
password: <%= ENV['DB_PASSWORD'] %>
database: <%= ENV['DB_DATABASE'] %>
...
It's workable solution, but seems like step-backward.
As I know now, we cant use ENV-vars in credentials any simple way.

Rails 5.2 credentials:edit doesn't like secret_key_base

I've been trying to debug my credentials file in my staging server. Whenever I try to edit the credentials on my staging server, I get the following error:
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:583:in `validate_secret_key_base': `secret_key_base` for staging environment must be a type of String`
My database.yml file looks like the following:
---
default: &default
adapter: postgresql
development:
<<: *default
database: dev_db
host: <%= Rails.application.credentials.database.fetch(:development).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:development).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:development).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:development) %>
test:
<<: *default
database: test_db
host: <%= Rails.application.credentials.database.fetch(:development).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:development).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:development).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:development) %>
staging:
<<: *default
database: <%= Rails.application.credentials.database.fetch(:staging).fetch(:name) %>
host: <%= Rails.application.credentials.database.fetch(:staging).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:staging).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:staging).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:staging) %>
production:
<<: *default
database: <%= Rails.application.credentials.database.fetch(:production).fetch(:name) %>
host: <%= Rails.application.credentials.database.fetch(:production).fetch(:host) %>
username: <%= Rails.application.credentials.database.fetch(:production).fetch(:username) %>
password: <%= Rails.application.credentials.database.fetch(:production).fetch(:password) %>
secret_key_base: <%= Rails.application.credentials.secret_key_base.fetch(:production) %>
I think my staging's secret_key_base is of type String. I generated my secret_key_base using rails secret. Locally, when I bring up the rails console, I can view the secret_key_bases for my staging environment:
[1] pry(main)> Rails.application.credentials.secret_key_base.fetch(:staging)
\=> "generated_using_rails_secret"
It returns a string but I still get the error message above whenever I try to access credentials in my staging environment.
I ended up looking at the stack trace and digging into the railties-5.2.0 gem.
Abbreviated stack trace:
ArgumentError: `secret_key_base` for staging environment must be a type of String`
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:583:in `validate_secret_key_base'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:432:in `secret_key_base'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:176:in `key_generator'
/var/www/bundle/ruby/2.5.0/gems/railties-5.2.0/lib/rails/application.rb:205:in `message_verifier'
I ended up looking in railties-5.2.0/lib/rails/application.rb:432: and seeing the following bit of code:
# The secret_key_base is used as the input secret to the application's key generator, which in turn
# is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies.
#
# In test and development, this is simply derived as a MD5 hash of the application's name.
#
# In all other environments, we look for it first in ENV["SECRET_KEY_BASE"],
# then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
# the correct place to store it is in the encrypted credentials file.
def secret_key_base
if Rails.env.test? || Rails.env.development?
Digest::MD5.hexdigest self.class.name
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
I had mistakenly thought I could specify a SECRET_KEY_BASE for an individual environment. Instead, I could only specify one secret key base. The secret key base apparently has nothing to do with database.yml. I need to read up on it and what it actually does.
If you run rails credentials:edit from the command line it will decrypt the config/credentials.yml.enc file.
You can then edit this file to add environment based secret keys like you would have previously added to config/secrets.yml.
When you save this file it will be encrypted again with the new information included.
There is no reason to have the "secret_key_base" in your database.yml file as this will not have any impact.
Nice Article on the new Rails credentials
Additionally just because rails now longer generates a config/secrets.yml file for you, as of rails 5.2, adding one will still work appropriately as it has in previous releases.

Figaro store passwords rails

I have install figaro gem.
My application.yml file:
user: 'm#am.com'
pwd: = 'password123'
Also I have in secrets.yml this:
development:
secret_key_base: d2c6dc60d0c86d32c71aa2ec2ae1fff32f338187ceaa12f0d6a294f368760ead01bc1c57115d48b80ab4042b45ca5aceadea1e888f34b5a14ab548eb07e1ad9c
test:
secret_key_base: f4c0aad565527a57110ccba77def71e2dd1b65799b94d4d24f9b34a8bc42fd01dbc64349c5555dca46b4d5d2ba85f890c718c1de0d20237704c788e4db928c66
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_token: ENV["secret_token"]
secret_key_base: ENV["secret_key_base"]
user: ENV["user"]
pwd: ENV["pwd"]
key: ENV["key"]
And I get user login like this:
Rails.application.secrets[:user]
Which gives me exactly this value:
"ENV[\"user\"]"
So what do I do?
seems like I should use
ENV["key"]
instead of Rails.application.secrets[:user]

Ruby on Rails, retrieving API key from secrets.yml

Can someone help me understand how to retrieve an API key if I'm storing it into secrets.yml?
If I have some kind of google API key 'yt_key':
secrets.yml
development:
secret_key_base: 390257802398523094820 #some key
yt_key: A423092389042430 #some key
test:
secret_key_base: 43208947502938530298525#some key
yt_key: A423092389042430 #some key
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
yt_key: <%= ENV["YT_KEY"] %>
I'm just following the examples, this is how I would set it up right?
So if I publish this to production, I would save the A423092389042430 in heroku and under YT_KEY, correct?
But in development, would I do it this way to retrieve the data:
in /config/application.rb
Yt.configure do |config|
config.api_key = '<%= ENV["YT_KEY"] %>'
end
or should this be in the the class:
module Sample
class Application < Rails::Application
Yt.configure do |config|
config.api_key = '<%= ENV["YT_KEY"] %>'
end
config.active_record.raise_in_transactional_callbacks = true
end
end
Or did I set up the configure wrong?
ENV["YT_KEY"] references the 'YT_KEY' environment variable which you'll have to set with a Heroku config variable.
In your app, you can access your secrets like this:
Rails.application.secrets.key_name
Since you're storing the 'YT_KEY' as an environment variable in production only, you should configure Yt like so:
(You can do this in a initializer file located at app/initializers/yt.rb)
Yt.configure do |config|
config.api_key = Rails.application.secrets.yt_key
end
That way, the correct key will be set in each environment.
It's good practice to use different keys for each environment, so should get another key for your production environment. Also, you should avoid storing secret production environment keys in the code. That's why it's common to use ENV variables for production keys.
Let me know if you need any clarification!
Do it this way, we are doing this way since a long time and working very well for us and this is a good convention as well.
secrets.yml
development:
secret_key_base: 390257802398523094820 #some key
yt_key: A423092389042430 #some key
test:
secret_key_base: 43208947502938530298525#some key
yt_key: A423092389042430 #some key
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
yt_key: <%= ENV["YT_KEY"] %>
Add these line to your application.rb file
config_files = ['secrets.yml']
config_files.each do |file_name|
file_path = File.join(Rails.root, 'config', file_name)
config_keys = HashWithIndifferentAccess.new(YAML::load(IO.read(file_path)))[Rails.env]
config_keys.each do |k,v|
ENV[k.upcase] ||= v
end
end
and now you can access yt_key this way ENV["YT_KEY"] or any other key you add like some_key to ENV["SOME_KEY"].
It's often recommended to not put your custom keys in secret.yml instead make another file like app_keys.yml and put all keys there.
You can also use Figaro gem.
Once installed, you'll have a config/application.yml file. Inside it you can store your api keys etc.:
SENDGRID_USERNAME: a-name
SENDGRID_PASSWORD: password
Now, anywhere in your .rb files, you can reference it using vars:
# Noticed how I keep my vars uppercase throughout.
ENV["SENDGRID_USERNAME"]
ENV["SENDGRID_PASSWORD"]
# Production vars go below the `production` line
production:
ENV["MY_PRODUCTION_VAR"]
If using those env keys inside your html.erb then you'll need to wrap it with <%= ... %>

devise with omniauth - setting a seperate config for dev and production

I'm using omniauth, with devise, to allow sign on through Facebook in my app.
My devise.rb file has the following line
config.omniauth :facebook, 'MY_DEV_APP_ID', 'MY_DEV_APP_SECRET'
I have 2 apps on facebook, one pointing to my live url & the other to my dev url.
How do I add two separate omniauth configs to the devise rb file?
something like -
if ENV['RAILS_ENV'] = "production"
config.omniauth :facebook, 'MY_LIVE_APP_ID', 'MY_LIVE_APP_SECRET'
else
config.omniauth :facebook, 'MY_DEV_APP_ID', 'MY_DEV_APP_SECRET'
end
More importantly, should I be putting this in the devise.tb file or should it be seperated into my production.rb & devleopment.rb files? If so, how do I reference it in my devise.rb file?
My method for this is to store them in a yaml file. I call mine config/api_keys.yml
defaults: &defaults
twitter:
api_key: "KEY"
api_secret: "SECRET"
facebook:
api_key: "KEY"
api_secret: "SECRET"
development:
<<: *defaults
test:
<<: *defaults
production:
twitter:
api_key: "KEY2"
api_secret: "SECRET2"
facebook:
api_key: "KEY2"
api_secret: "SECRET2"
Then in my devise.rb file I do:
API_KEYS = YAML::load_file("#{Rails.root}/config/api_keys.yml")[Rails.env]
config.omniauth :facebook , API_KEYS['facebook']['api_key'], API_KEYS['facebook']['api_secret']
config.omniauth :twitter , API_KEYS['twitter']['api_key'], API_KEYS['twitter']['api_secret']
As a good practice, you probably shouldn't store your production API keys in this file in version control. You should store it on the server and symlink it over in your deploy script, like you would database.yml

Resources