fnando/access_token

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# AccessToken

[![Travis-CI](https://travis-ci.org/fnando/access_token.png)](https://travis-ci.org/fnando/access_token)
[![Code Climate](https://codeclimate.com/github/fnando/access_token/badges/gpa.svg)](https://codeclimate.com/github/fnando/access_token)
[![Test Coverage](https://codeclimate.com/github/fnando/access_token/badges/coverage.svg)](https://codeclimate.com/github/fnando/access_token/coverage)
[![Gem](https://img.shields.io/gem/v/access_token.svg)](https://rubygems.org/gems/access_token)
[![Gem](https://img.shields.io/gem/dt/access_token.svg)](https://rubygems.org/gems/access_token)

A simple and easy-to-use access token generator.

## Installation

Add this line to your application's Gemfile:

```ruby
gem "access_token"
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install access_token

## Usage

```ruby
class ApplicationController < ActionController::Base
  private

  def access_token
    @access_token ||= AccessToken.new(
      request: request,
      response: response,
      secret: Rails.application.secrets.access_token_secret,
      ttl: 3600
    )
  end

  def current_user
    @current_user
  end

  def authenticate
    @current_user = User.find_by_id(access_token.resolve)
    return render(nothing: true, status: 401) unless current_user
    access_token.update(current_user)
  end
end

class AuthController < ApplicationController
  def create
    user = User.find_by_email(params[:email].to_s)
            .try(:authenticate, params[:password].to_s)

    if user
      access_token.update(user)
      render json: user
    else
      render nothing: true, status: 401
    end
  end
end

class ProfileController < ApplicationController
  before_action :authenticate

  def show
    render json: current_user
  end
end

Rails.application.routes.draw do
  get "/profile", to: "profile#show"
  post "/auth", to: "auth#create"
end
```

Now, testing authentication using [httpie](http://httpie.org).

```
$ http --form POST localhost:3000/auth email=john@example.com password=test
HTTP/1.1 200 OK
Bearer: 5A2tPbDOXrQSMH1WzsEhhPaw4rNa1sJ9j7OyAU6gr1kfaZM0xDiXUGuENKyKLC/rKuzhrDXG6FwehWhIWy3IMfhQ9n6FJwBCERlF1TavYo2lG0UM8Bz1/0vrz3DxJc/r
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 196
Content-Type: application/json; charset=utf-8
Date: Mon, 01 Jun 2015 00:22:12 GMT
Etag: W/"a710bcbfd462f6c4f7fed6bd7cff32b5"
Expires: Mon, 01 Jun 2015 01:22:12 GMT
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: e4a07ab3-fa31-4058-aad5-2bcb5ce1f16e
X-Runtime: 0.102162
X-Xss-Protection: 1; mode=block

{
    "created_at": "2015-06-01T00:08:46.308Z",
    "email": "john@example.com",
    "id": 1,
    "password_digest": "$2a$10$ayl6Yj.Hu1s.sba11YuMpOwDX.fZ.zsj.lPAvyapgLf6FWZtin.FW",
    "updated_at": "2015-06-01T00:08:46.308Z"
}
```

You can use the bearer by setting the `Authorization` header.

```
$ http GET localhost:3000/profile Authorization:'Bearer 5A2tPbDOXrQSMH1WzsEhhPaw4rNa1sJ9j7OyAU6gr1kfaZM0xDiXUGuENKyKLC/rKuzhrDXG6FwehWhIWy3IMfhQ9n6FJwBCERlF1TavYo2lG0UM8Bz1/0vrz3DxJc/r'
HTTP/1.1 200 OK
Bearer: 5A2tPbDOXrQSMH1WzsEhhAgjsNRUhdJ6MZkah4PAU8840fSkebzmJpooRIkcc3csBafqjm5tR+nPbnydN1N378bXQtxvKr6m5doHp/rhCYYF+PbR72NE37Q/DpRgg577
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 196
Content-Type: application/json; charset=utf-8
Date: Mon, 01 Jun 2015 00:23:03 GMT
Etag: W/"a710bcbfd462f6c4f7fed6bd7cff32b5"
Expires: Mon, 01 Jun 2015 01:23:03 GMT
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 45ee363e-5df5-4514-b625-d4eb1dcb2e2a
X-Runtime: 0.024450
X-Xss-Protection: 1; mode=block

{
    "created_at": "2015-06-01T00:08:46.308Z",
    "email": "john@example.com",
    "id": 1,
    "password_digest": "$2a$10$ayl6Yj.Hu1s.sba11YuMpOwDX.fZ.zsj.lPAvyapgLf6FWZtin.FW",
    "updated_at": "2015-06-01T00:08:46.308Z"
}
```

Notice that a new bearer is returned every time you call `access_token.update(current_user)`.

If you're using Redis or Memcached store, you can't use the same bearer twice.

```
$ http GET localhost:3000/profile Authorization:'Bearer 5A2tPbDOXrQSMH1WzsEhhPaw4rNa1sJ9j7OyAU6gr1kfaZM0xDiXUGuENKyKLC/rKuzhrDXG6FwehWhIWy3IMfhQ9n6FJwBCERlF1TavYo2lG0UM8Bz1/0vrz3DxJc/r'
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 0
Content-Type: text/plain; charset=utf-8
Date: Mon, 01 Jun 2015 00:23:23 GMT
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 401c9b61-824c-44a0-8cd2-faab545127cc
X-Runtime: 0.024320
X-Xss-Protection: 1; mode=block
```

Also, check out the `examples` directory.

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, 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` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

1. Fork it ( https://github.com/fnando/access_token/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request