Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
TokenSecretAuth aims to be a simple implementation of token+secret authentication.
Clients using this can send a token + secret that looks like: { token: "koV3Zel321fe", secret: "fffixk5ptz2puaf1sk3wo5szpkrpjnhp" }
token is a hashed form of the model id
secret is randomly assigned and can be encrypted using has_secure_password
or a similar implementation.
OR Why did you release this?
Many APIs use a token or a token+secret to authenticate API clients. If that token+secret grants similar power as a login+password it should be protected just like a password
However, while looking for a gem to handle mobile API authentication I found that many solutions fit into one of two categories:
.find(id)
and works with or in a manner similar to has_secure_password
will work. (model instance should respond to model_instance#password=
)Add this line to your application's Gemfile:
gem 'token_secret_auth'
And then execute:
$ bundle
Or install it yourself as:
$ gem install token_secret_auth
In your model file add:
include TokenSecretAuth
This grants your model instances the following methods:
#token, #decode_token, #generate_secret
Also add to the model:
has_secure_password
Create and run a migration to add the password_digest
field to your model.
For example on rails:
$ rails generate migration AddPasswordDigestToApiClients password_digest:string
Note: you do not need a 'token' field on your model. #token
is a virtual attribute derived from the model ID. password
is your secret.
Tokens are generated from the model ID.
SomeModel.find(1000).token # => o9WM01OR1jgD
Secrets are randomly generated by Model.generate_secret
or #generate_secret
.
Store the secret using #password=
or similar encrypted functionality.
client = ApiClient.find_by_token('afuoisjdjl') # or ApiClient.new
client.password = client.generate_secret
client.save # bcrypt/has_secure_password will handle encryption
On Rails you may want to use callbacks to generate the password automatically:
before_validation :generate_secret, on: [ :new, :create ]
Calling
generate_secret
on an instance will automatically set password to the new secret.
If your API allows a client to login and then receive a new API token+secret the responding controller method may look something like this.
def try_login
@email = login_params[:email]
@pass = login_params[:password]
@user = User.find_by(email: @email).try(:authenticate, @pass)
if @user
api_client = @user.api_clients.create
# IMPORTANT - this is the only time you can see the secret decrypted
render json: { token: api_client.token, secret: api_client.secret }
else
render json: {password: ["Invalid account or password"]}, status: :unauthorized
end
end
To perform authentication with the token + secret, for example as a before_action
in an ApplicationController
:
def current_user
if params[:credentials]
token = credentials_params[:token]
secret = credentials_params[:secret]
begin
api_client = ApiClient.authenticate_by_credentials(token, secret)
rescue ActiveRecord::RecordNotFound
# if someone sends a decodable token but the record doesn't exist
end
end
if api_client
@current_user = api_client.user
else
render json: {errors: ['Unauthorized token or secret']}, status: :unauthorized }
end
end
If you'd like to change the salt used for hashing IDs to generate token
s you can add an initializer:
# config/initializers/token_secret_auth.rb
TokenSecretAuth.configure do |config|
config.id_salt = 'some appropriately salty bytes'
end
Note: the salt used for hashing the secret (password) is controlled by your BCrypt config.
Devise is a great solution and I often recommend it. However, it is sometimes more complexity than needed for something this simple. TokenSecretAuth does not require devise.
If your token or token+secret grants a user similar power as a login+password then it should be encrypted with one-way encryption just like a password.
The secret is the password field on the model. It's only available when the instance is first created after that you can't retrieve it - - that's the whole point of one-way encryption.
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/tgaff/token_secret_auth. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the TokenSecretAuth project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
FAQs
Unknown package
We found that token_secret_auth demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.