Skip to content

Commit

Permalink
Encrypt token and refresh token with AR encryption (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
jalyna authored Apr 26, 2022
1 parent 2a2c798 commit fcb37cf
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

* **BREAKING:** Encrypt `token` & `refresh_token` with [Active Record Encryption](https://guides.rubyonrails.org/active_record_encryption.html#setup):
1. Run `rails db:encryption:init` per environment and copy the values to your encrypted credentials
2. Run `rails zaikio_oauth_client:install:migrations` and `rails db:migrate` to encrypt stored access tokens

## 0.17.2 - 2022-01-07

* Fix broken Rubocop auto-corrected code.
Expand Down
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@ Then run `bundle install`.

## Setup & Configuration

### 1. Copy & run Migrations
### 1. Setup Active Record encryption

Setup [Active Record Encryption](https://guides.rubyonrails.org/active_record_encryption.html#setup) by running:

```
rails db:encryption:init
```

(Continue generating the credentials each for different environments)

### 2. Copy & run Migrations

```bash
rails zaikio_oauth_client:install:migrations
Expand All @@ -24,15 +34,15 @@ rails db:migrate
This will create the tables:
+ `zaikio_access_tokens`

### 2. Mount routes
### 3. Mount routes

Add this to `config/routes.rb`:

```rb
mount Zaikio::OAuthClient::Engine => "/zaikio"
```

### 3. Configure Gem
### 4. Configure Gem

```rb
# config/initializers/zaikio_oauth_client.rb
Expand Down Expand Up @@ -70,7 +80,7 @@ end
```


### 4. Clean up outdated access tokens (recommended)
### 5. Clean up outdated access tokens (recommended)

To avoid keeping all expired oath and refresh tokens in your database, we recommend to implement their scheduled deletion. We recommend therefore to use a schedule gems such as [sidekiq](https://github.com/mperham/sidekiq) and [sidekiq-scheduler](https://github.com/moove-it/sidekiq-scheduler).

Expand Down
4 changes: 4 additions & 0 deletions app/models/zaikio/access_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ module Zaikio
class AccessToken < ApplicationRecord
self.table_name = "zaikio_access_tokens"

# Encryption
encrypts :token
encrypts :refresh_token

def self.build_from_access_token(access_token, requested_scopes: nil)
payload = JWT.decode(access_token.token, nil, false).first rescue {} # rubocop:disable Style/RescueModifier
scopes = access_token.params["scope"].split(",")
Expand Down
45 changes: 45 additions & 0 deletions db/migrate/20220425130923_encrypt_tokens.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class EncryptTokens < ActiveRecord::Migration[7.0]
def change
reversible do |dir|
dir.up do
rename_column :zaikio_access_tokens, :token, :unencrypted_token
rename_column :zaikio_access_tokens, :refresh_token, :unencrypted_refresh_token

add_column :zaikio_access_tokens, :token, :string
add_column :zaikio_access_tokens, :refresh_token, :string

Zaikio::AccessToken.find_each do |access_token|
access_token.update(
token: access_token.unencrypted_token,
refresh_token: access_token.unencrypted_refresh_token
)
end

change_column_null :zaikio_access_tokens, :token, false

remove_column :zaikio_access_tokens, :unencrypted_token, :string
remove_column :zaikio_access_tokens, :unencrypted_refresh_token, :string
end

dir.down do
add_column :zaikio_access_tokens, :unencrypted_token, :string
add_column :zaikio_access_tokens, :unencrypted_refresh_token, :string

Zaikio::AccessToken.find_each do |access_token|
access_token.update_columns(
unencrypted_token: access_token.token,
unencrypted_refresh_token: access_token.refresh_token
)
end

remove_column :zaikio_access_tokens, :token, :string
remove_column :zaikio_access_tokens, :refresh_token, :string

rename_column :zaikio_access_tokens, :unencrypted_token, :token
rename_column :zaikio_access_tokens, :unencrypted_refresh_token, :refresh_token

change_column_null :zaikio_access_tokens, :token, false
end
end
end
end
2 changes: 1 addition & 1 deletion test/dummy/.ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.6.5
3.0.2
1 change: 1 addition & 0 deletions test/dummy/config/credentials.yml.enc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MsRV2Mg6x6Jq0eu3/BZShLSbtGT5bWyTIfk2ZVtAqZNYZpfWe9p5OBg+q0oG3d5CQ/LNBoR+3QyhKWq1VedEYFMAPmOHVJMyf45zA+a8oZrKBE5j8TbH7AwxDhS9qhOcgKy4wyjG9El/GfwsHbxABISPirX4lZZVVndA7BmOCd5HdEAOJaPS36StKOfFxZRZhLfoFvXZtdL7QaSeaIb4Aq61NAIZcHHtDT3FhpwMxe9htdEM+WyxJwN+RY90x6nYWz+nG1sUXOMOSjgbtXpbUK/9lmQli+XQ5jvJ4fzczrKNxy1458ofLdQfoDKyj0M07NQ12RH/CXYCXYMbIU+on2XMEtg0yQLXE/XumxRlvvpuUUAAGNB+W5YlqsoHtPkwAYp4qD1ELVlrmnBSJ+2XR7K93DZpc3xaJpjGNvEWmRMSM/dJT5DN0LTCyNenXLVHcy7AAXe0vkH9nRU3upitgRE3r5x98XIgFWGgQbETZwFpa/qH5EMKKj7PsiLeIamSHz3JzwaJ4sTA0QzlzrnnvPPy+QcrzjtGVkeDg480o8sGG7kb9NhCWBu5d9Dpppzn+q4nPudXubetbEQNPseJm6jmvJH0L+M38ljvTmHiArgbLVcolGetUnwJRUdgG9efZb/kbTEAN2QusB3AduU=--PoFKtd9aCQeg0nfQ--Ly9kRlHlfRlttygGvwzK0g==
1 change: 1 addition & 0 deletions test/dummy/config/master.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ecef4dc720bff4d182a567e35b19daf7
9 changes: 3 additions & 6 deletions test/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2021_02_24_154303) do

ActiveRecord::Schema[7.0].define(version: 2022_04_25_130923) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
Expand All @@ -20,17 +19,15 @@
t.string "bearer_type", default: "Organization", null: false
t.string "bearer_id", null: false
t.string "audience", null: false
t.string "token", null: false
t.string "refresh_token"
t.datetime "expires_at"
t.string "scopes", default: [], null: false, array: true
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "requested_scopes", default: [], null: false, array: true
t.string "token", null: false
t.string "refresh_token"
t.index ["audience", "bearer_type", "bearer_id"], name: "zaikio_access_tokens_lookup_index"
t.index ["expires_at"], name: "index_zaikio_access_tokens_on_expires_at"
t.index ["refresh_token"], name: "index_zaikio_access_tokens_on_refresh_token", unique: true
t.index ["token"], name: "index_zaikio_access_tokens_on_token", unique: true
end

end

0 comments on commit fcb37cf

Please sign in to comment.