Giter Club home page Giter Club logo

authn-rb's Introduction

Keratin AuthN

Keratin AuthN is an authentication service that keeps you in control of the experience without forcing you to be an expert in web security.

This gem provides utilities to help integrate with the backend of a Ruby application. You will also need a client for your frontend, such as keratin/authn-js.

Gitter Gem Version Build Status Coverage Status

Installation

Add this line to your application's Gemfile:

gem 'keratin-authn'

Usage

Configure your integration from a file such as config/initializers/keratin.rb:

Keratin::AuthN.config.tap do |config|
  # The AUTHN_URL of your Keratin AuthN server. This will be used to verify tokens created by AuthN,
  # and will also be used for API calls unless `config.authn_url` is also set (see below).
  config.issuer = 'https://authn.myapp.com'

  # The domain of your application (no protocol). This domain should be listed in the APP_DOMAINS of
  # your Keratin AuthN server.
  config.audience = 'myapp.com'

  # Credentials for AuthN's private endpoints. These will be used to execute admin actions using the
  # `Keratin.authn` client provided by this library.
  #
  # TIP: make them extra secure in production!
  config.username = 'secret'
  config.password = 'secret'

  # OPTIONAL: enables debugging for the JWT verification process
  # config.logger   = Rails.logger

  # OPTIONAL: Send private API calls to AuthN using private network routing. This can be necessary
  # if your environment has a firewall to limit public endpoints.
  # config.authn_url = 'https://authn.internal.dns/
end

Reading the Session

Use Keratin::AuthN.subject_from(params[:authn]) to fetch an account_id from the session if and only if the session is valid.

Modifying Accounts

  • Keratin.authn.update(account_id, username: '[email protected]'): will synchronize an email change with the AuthN server.
  • Keratin.authn.lock(account_id): will lock an account, revoking all sessions (when they time out) and disallowing any new logins. Intended for user moderation actions.
  • Keratin.authn.unlock(account_id): will unlock an account, restoring normal functionality.
  • Keratin.authn.archive(account_id): will wipe all personal information, including username and password. Intended for user deletion routine.
  • Keratin.authn.expire_password(account_id): will force the account to reset their password on the next login, and revoke all current sessions. Intended for use when password is deemed insecure or otherwise expired.

Other

  • Keratin.authn.import(username: user.email, password: user.password, locked: false): will create an account in Keratin. Intended for importing data from a legacy system. Returns an account_id, or raises on validation errors.

Example: Sessions

You should store the token in a cookie (the keratin/authn-js integration can do this automatically) and continue using it to verify a logged-in session:

class ApplicationController
  private

  def logged_in?
    !! current_account_id
  end

  def current_user
    return @current_user if defined? @current_user
    @current_user = User.find_by_account_id(current_account_id)
  end

  def current_account_id
    Keratin::AuthN.subject_from(cookies[:authn])
  end
end

Example: Signup

class UsersController
  def create
    @user = User.new(params.require(:user).permit(:name, :email))
    @user.account_id = current_account_id

    # ...
  end
end

Example: Login

class SessionsController
  def create
    @user = current_user

    # ...
  end
end

Example: Multiple Domains

When working with multiple frontend domains it may be beneficial to use a referrer header as your audience instead of a static configuration. You can do this by providing an additional parameter to the subject_from method.

class ApplicationController
  private

  def current_user
    return @current_user if defined? @current_user
    @current_user = User.find_by_account_id(current_account_id)
  end

  def current_account_id
    Keratin::AuthN.subject_from(cookies[:authn], audience: URI.parse(request.referer).host)
  end
end

Testing Your App

AuthN provides helpers for working with tokens in your application's controller and integration tests.

In your test/test_helper.rb or equivalent:

# Configuring AuthN to use the MockKeychain will stop your tests from attempting to connect to the
# remote issuer during tests. The MockKeychain creates a single weak key, for speedy tests.
Keratin::AuthN.keychain = Keratin::AuthN::MockKeychain.new

# Including the Test::Helpers module grants access to `id_token_for(user.account_id)`, so that you
# can test your system with real tokens.
module ActionDispatch
  class IntegrationTest
    include Keratin::AuthN::Test::Helpers
  end
end

Developing AuthN

After checking out the repo, run bin/setup to install dependencies. Then, run rake test 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.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/keratin/authn-rb. 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.

authn-rb's People

Contributors

cainlevy avatar nathanpalmer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

authn-rb's Issues

Better information for failed logins

Hey @cainlevy, I'm curious, are you open to extending this project so that the caller of subject_from can get better information than the id token verification worked/failed?

One way I have implemented this is, is by raising errors in the verifier and then catching that error in the application controller and then returning the error's message to the client. I have found this very helpful when working on projects so that you can know why the login failed.

Thoughts?

allow configuring a separate URL for private endpoints

Configuration should allow a separate URL for issuing requests to private endpoints.

This is intended to solve a tricky bit of setup in deployments where communication between services goes over a private network. Currently, this setup requires configuring authn-server and the backend with the private URL as issuer, while configuring the frontend with the public URL.

  • config.issuer: must match the iss claim in authn-server tokens
  • config.authn_url: provides the base url for private communication with authn-server (defaults to config.issuer)

Working with multiple frontend domains

The audience is setup as a static configuration within this library which makes it currently impossible to allow a single backend to service multiple front-end domains.

From the README.md example it shows this configuration

Keratin::AuthN.config.tap do |config|
  # The base URL of your Keratin AuthN service
  config.issuer = 'https://authn.myapp.com'

  # The domain of your application
  config.audience = 'myapp.com'

  # HTTP basic auth for using AuthN's private endpoints
  config.username = 'secret'
  config.password = 'secret'
end

and within id_token_verifier.rb it's grabbing the audience out of the configuration for verification.

def token_for_us?
  jwt[:aud] == Keratin::AuthN.config.audience
end

However, if we have multiple frontend servers hitting the same backend API we will only be able to service one of them.

  • frontend1.domain.com -> api.domain.com
  • frontend2.domain.com -> api.domain.com

I can set the configuration to one or the other but not both. It would be nice if we could pass a parameter (maybe optional) into subject_from as an audience override. That way we can take the referrer header from the request and pass it through. That should allow for the audience verification but allow it to work a bit more dynamically.

refactor key fetching to rely on configured issuer

Currently, JWKs are fetched from the JWT iss after verifying that the iss is equivalent to the configuration. This should be refactored so that keys are fetched directly from the configured issuer and made available to the token verifier by kid.

The expected benefit is a clearer verification process that does not depend on transitive trust

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.