api_keys 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +393 -0
- data/Rakefile +32 -0
- data/api_keys_dashboard.webp +0 -0
- data/api_keys_permissions.webp +0 -0
- data/api_keys_token.webp +0 -0
- data/app/controllers/api_keys/application_controller.rb +62 -0
- data/app/controllers/api_keys/keys_controller.rb +129 -0
- data/app/controllers/api_keys/security_controller.rb +16 -0
- data/app/views/api_keys/keys/_form.html.erb +106 -0
- data/app/views/api_keys/keys/_key_row.html.erb +72 -0
- data/app/views/api_keys/keys/_keys_table.html.erb +52 -0
- data/app/views/api_keys/keys/_show_token.html.erb +88 -0
- data/app/views/api_keys/keys/edit.html.erb +5 -0
- data/app/views/api_keys/keys/index.html.erb +26 -0
- data/app/views/api_keys/keys/new.html.erb +5 -0
- data/app/views/api_keys/keys/show.html.erb +12 -0
- data/app/views/api_keys/security/best_practices.html.erb +70 -0
- data/app/views/layouts/api_keys/application.html.erb +115 -0
- data/config/routes.rb +18 -0
- data/lib/api_keys/authentication.rb +160 -0
- data/lib/api_keys/configuration.rb +125 -0
- data/lib/api_keys/controller.rb +47 -0
- data/lib/api_keys/engine.rb +76 -0
- data/lib/api_keys/jobs/callbacks_job.rb +69 -0
- data/lib/api_keys/jobs/update_stats_job.rb +58 -0
- data/lib/api_keys/logging.rb +42 -0
- data/lib/api_keys/models/api_key.rb +209 -0
- data/lib/api_keys/models/concerns/has_api_keys.rb +144 -0
- data/lib/api_keys/services/authenticator.rb +255 -0
- data/lib/api_keys/services/digestor.rb +68 -0
- data/lib/api_keys/services/token_generator.rb +32 -0
- data/lib/api_keys/tenant_resolution.rb +40 -0
- data/lib/api_keys/version.rb +5 -0
- data/lib/api_keys.rb +49 -0
- data/lib/generators/api_keys/install_generator.rb +70 -0
- data/lib/generators/api_keys/templates/create_api_keys_table.rb.erb +100 -0
- data/lib/generators/api_keys/templates/initializer.rb +160 -0
- metadata +184 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "base58"
|
5
|
+
|
6
|
+
module ApiKeys
|
7
|
+
module Services
|
8
|
+
# Generates secure, random API tokens according to configured settings.
|
9
|
+
class TokenGenerator
|
10
|
+
# Generates a new token string.
|
11
|
+
#
|
12
|
+
# @param length [Integer] The desired byte length of the random part (before encoding).
|
13
|
+
# @param prefix [String] The prefix to prepend to the token.
|
14
|
+
# @param alphabet [Symbol] The encoding alphabet (:base58 or :hex).
|
15
|
+
# @return [String] The generated token including the prefix.
|
16
|
+
def self.call(length: ApiKeys.configuration.token_length, prefix: ApiKeys.configuration.token_prefix.call, alphabet: ApiKeys.configuration.token_alphabet)
|
17
|
+
random_bytes = SecureRandom.bytes(length)
|
18
|
+
|
19
|
+
random_part = case alphabet
|
20
|
+
when :base58
|
21
|
+
Base58.binary_to_base58(random_bytes, :bitcoin)
|
22
|
+
when :hex
|
23
|
+
random_bytes.unpack1("H*") # Equivalent to SecureRandom.hex
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Unsupported token alphabet: #{alphabet}. Use :base58 or :hex."
|
26
|
+
end
|
27
|
+
|
28
|
+
"#{prefix}#{random_part}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module ApiKeys
|
6
|
+
# Controller concern to resolve and provide access to the tenant
|
7
|
+
# associated with the currently authenticated API key.
|
8
|
+
module TenantResolution
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
helper_method :current_api_tenant
|
13
|
+
|
14
|
+
# Alias for convenience and explicitness
|
15
|
+
alias_method :current_api_key_tenant, :current_api_tenant
|
16
|
+
alias_method :current_api_account, :current_api_tenant
|
17
|
+
alias_method :current_api_key_account, :current_api_tenant
|
18
|
+
alias_method :current_api_owner, :current_api_tenant
|
19
|
+
alias_method :current_api_key_owner, :current_api_tenant
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the tenant associated with the current API key.
|
23
|
+
# Uses the configured `tenant_resolver` lambda.
|
24
|
+
# Returns nil if no key is authenticated, no owner exists,
|
25
|
+
# or the resolver returns nil.
|
26
|
+
#
|
27
|
+
# @return [Object, nil] The resolved tenant object, or nil.
|
28
|
+
def current_api_tenant
|
29
|
+
return @current_api_tenant if defined?(@current_api_tenant)
|
30
|
+
return nil unless current_api_key # Requires Authentication concern to be included first
|
31
|
+
|
32
|
+
resolver = ApiKeys.configuration.tenant_resolver
|
33
|
+
@current_api_tenant = resolver&.call(current_api_key)
|
34
|
+
rescue StandardError => e
|
35
|
+
# Log error but don't break the request if resolver fails
|
36
|
+
Rails.logger.error "[ApiKeys] Tenant resolution failed: #{e.message}" if defined?(Rails.logger)
|
37
|
+
@current_api_tenant = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/api_keys.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This is the entry point to the gem.
|
4
|
+
|
5
|
+
require "rails"
|
6
|
+
require "active_record"
|
7
|
+
require "active_support/all"
|
8
|
+
|
9
|
+
require "api_keys/version"
|
10
|
+
require "api_keys/configuration"
|
11
|
+
|
12
|
+
require "api_keys/models/concerns/has_api_keys"
|
13
|
+
|
14
|
+
require "api_keys/models/api_key"
|
15
|
+
|
16
|
+
# Rails integration
|
17
|
+
require "api_keys/engine" if defined?(Rails)
|
18
|
+
|
19
|
+
# Main module that serves as the primary interface to the gem.
|
20
|
+
# Most methods here delegate to Configuration, which is the single source of truth for all config in the initializer
|
21
|
+
module ApiKeys
|
22
|
+
# Custom error classes
|
23
|
+
class Error < StandardError; end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
attr_writer :configuration
|
27
|
+
|
28
|
+
def configuration
|
29
|
+
@configuration ||= Configuration.new
|
30
|
+
end
|
31
|
+
|
32
|
+
# Configure the gem with a block (main entry point)
|
33
|
+
def configure
|
34
|
+
yield(configuration)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Resets the configuration to its default values.
|
38
|
+
# Useful for testing.
|
39
|
+
def reset_configuration!
|
40
|
+
@configuration = Configuration.new
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# TODO: Require other necessary files like configuration, engine, etc.
|
47
|
+
# require_relative "api_keys/configuration"
|
48
|
+
# require_relative "api_keys/engine"
|
49
|
+
# require_relative "api_keys/railtie" if defined?(Rails::Railtie)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
require "rails/generators/active_record"
|
5
|
+
|
6
|
+
module ApiKeys
|
7
|
+
module Generators
|
8
|
+
# Rails generator for installing the ApiKeys gem.
|
9
|
+
# Creates the necessary migration and initializer file.
|
10
|
+
class InstallGenerator < Rails::Generators::Base
|
11
|
+
include ActiveRecord::Generators::Migration
|
12
|
+
|
13
|
+
source_root File.expand_path("templates", __dir__)
|
14
|
+
|
15
|
+
# Implement the required interface for Rails::Generators::Migration.
|
16
|
+
# Borrowed from ActiveRecord::Generators::Base
|
17
|
+
# https://github.com/rails/rails/blob/main/activerecord/lib/rails/generators/active_record/base.rb#L31
|
18
|
+
def self.next_migration_number(dirname)
|
19
|
+
next_migration_number = current_migration_number(dirname) + 1
|
20
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates the migration file using the template.
|
24
|
+
def create_migration_file
|
25
|
+
migration_template "create_api_keys_table.rb.erb",
|
26
|
+
File.join(db_migrate_path, "create_api_keys_table.rb")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates the initializer file using the template.
|
30
|
+
def create_initializer
|
31
|
+
template "initializer.rb", "config/initializers/api_keys.rb"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Displays helpful information to the user after installation.
|
35
|
+
def display_post_install_message
|
36
|
+
say "\n🎉 api_keys gem successfully installed!", :green
|
37
|
+
say "\nNext steps:"
|
38
|
+
say " 1. Run `rails db:migrate` to create the `api_keys` table."
|
39
|
+
say " ☢️ Run migrations before starting your application!", :yellow
|
40
|
+
say "\n 2. Add `has_api_keys` to any models that need to have API keys, with an optional block for configuration:"
|
41
|
+
say " # Example for app/models/user.rb"
|
42
|
+
say " class User < ApplicationRecord"
|
43
|
+
say " has_api_keys do"
|
44
|
+
say " # Optional settings:"
|
45
|
+
say " # max_keys 10"
|
46
|
+
say " end"
|
47
|
+
say " # ..."
|
48
|
+
say " end"
|
49
|
+
say "\n 3. Optionally, configure the gem behavior in `config/initializers/api_keys.rb` if needed."
|
50
|
+
say "\n 4. In your app's API controllers, verify API keys by including `ApiKeys::Controller`, and adding the before_action to the desired endpoints:"
|
51
|
+
say " # Example for app/controllers/api/base_controller.rb"
|
52
|
+
say " class Api::BaseController < ActionController::API"
|
53
|
+
say " include ApiKeys::Controller"
|
54
|
+
say " before_action :authenticate_api_key! # Enforce authentication"
|
55
|
+
say " # ..."
|
56
|
+
say " end"
|
57
|
+
say "\nSee the api_keys README for detailed usage and examples.
|
58
|
+
", :cyan
|
59
|
+
say "Happy coding! 🚀", :green
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def migration_version
|
65
|
+
"[#{ActiveRecord::VERSION::STRING.to_f}]"
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Migration responsible for creating the core api_keys table.
|
4
|
+
class CreateApiKeysTable < ActiveRecord::Migration<%= migration_version %>
|
5
|
+
def change
|
6
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
7
|
+
|
8
|
+
create_table :api_keys, id: primary_key_type do |t|
|
9
|
+
# Identifiable prefix (e.g., "ak_live_", "ak_test_") for env/debugging
|
10
|
+
t.string :prefix, null: false
|
11
|
+
|
12
|
+
# Secure digest of the token (e.g., sha256 or bcrypt hash)
|
13
|
+
t.string :token_digest, null: false
|
14
|
+
|
15
|
+
# Algorithm used for the digest (e.g., "bcrypt", "sha256")
|
16
|
+
t.string :digest_algorithm, null: false
|
17
|
+
|
18
|
+
# Last 4 characters of the random part of the token for display
|
19
|
+
t.string :last4, null: false, limit: 4
|
20
|
+
|
21
|
+
# Optional, user-provided name for the key
|
22
|
+
t.string :name
|
23
|
+
|
24
|
+
# Who owns this key? Can be null for ownerless keys.
|
25
|
+
t.references :owner, polymorphic: true, null: true, type: foreign_key_type
|
26
|
+
|
27
|
+
# Optional list of permissions granted to this key (array of strings)
|
28
|
+
t.send(json_column_type, :scopes, default: [], null: false)
|
29
|
+
|
30
|
+
# Optional freeform metadata for tagging
|
31
|
+
t.send(json_column_type, :metadata, default: {}, null: false)
|
32
|
+
|
33
|
+
# Optional auto-expiration timestamp
|
34
|
+
t.datetime :expires_at
|
35
|
+
|
36
|
+
# Timestamp of the last successful authentication using this key
|
37
|
+
t.datetime :last_used_at
|
38
|
+
|
39
|
+
# Optional counter cache for total requests made with this key.
|
40
|
+
t.bigint :requests_count, default: 0, null: false
|
41
|
+
|
42
|
+
# Timestamp when the key was revoked (null means active)
|
43
|
+
t.datetime :revoked_at
|
44
|
+
|
45
|
+
t.timestamps
|
46
|
+
|
47
|
+
# Critical index for authentication performance
|
48
|
+
t.index :token_digest, unique: true
|
49
|
+
|
50
|
+
# Index to optimize prefix-based lookups (especially for bcrypt)
|
51
|
+
t.index [:prefix, :digest_algorithm], name: "index_api_keys_on_prefix_and_digest_algorithm"
|
52
|
+
|
53
|
+
# Optional indexes
|
54
|
+
t.index :prefix
|
55
|
+
t.index :last4 # Index potentially useful for UI lookups/filtering by masked token
|
56
|
+
t.index :owner_id if foreign_key_type # Index owner_id only if it's a separate column
|
57
|
+
t.index :owner_type if foreign_key_type # Index owner_type only if it's a separate column
|
58
|
+
t.index :expires_at
|
59
|
+
t.index :revoked_at
|
60
|
+
t.index :last_used_at
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Helper method to determine the appropriate primary and foreign key types
|
67
|
+
# based on the Rails application's configuration.
|
68
|
+
def primary_and_foreign_key_types
|
69
|
+
config = Rails.configuration.generators
|
70
|
+
setting = config.options[config.orm][:primary_key_type]
|
71
|
+
primary_key_type = setting || :primary_key
|
72
|
+
foreign_key_type = setting || :bigint # Assuming bigint is a safe default for foreign keys
|
73
|
+
[primary_key_type, foreign_key_type]
|
74
|
+
end
|
75
|
+
|
76
|
+
# Helper method to determine the appropriate JSON column type based on the database adapter.
|
77
|
+
# Uses :jsonb for PostgreSQL for better performance and indexing, :json otherwise.
|
78
|
+
def json_column_type
|
79
|
+
# Check connection availability for adapter name inspection
|
80
|
+
if ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
|
81
|
+
:jsonb
|
82
|
+
else
|
83
|
+
:json
|
84
|
+
end
|
85
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
86
|
+
# Fallback during initial setup or if connection isn't available
|
87
|
+
:text
|
88
|
+
end
|
89
|
+
|
90
|
+
# Provides the appropriate migration version syntax for the current Rails version.
|
91
|
+
def migration_version
|
92
|
+
major = ActiveRecord::VERSION::MAJOR
|
93
|
+
minor = ActiveRecord::VERSION::MINOR
|
94
|
+
if major >= 5
|
95
|
+
"[#{major}.#{minor}]"
|
96
|
+
else
|
97
|
+
""
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ApiKeys.configure do |config|
|
4
|
+
# === Core Authentication ===
|
5
|
+
|
6
|
+
# The HTTP header name where the API key is expected.
|
7
|
+
# Default: "Authorization" (expects "Bearer <token>")
|
8
|
+
# config.header = "Authorization"
|
9
|
+
|
10
|
+
# The query parameter name to check as a fallback if the header is missing.
|
11
|
+
# Set to nil to disable query parameter lookup (recommended for security).
|
12
|
+
# Default: nil
|
13
|
+
# config.query_param = "api_key"
|
14
|
+
|
15
|
+
# === Token Generation ===
|
16
|
+
|
17
|
+
# A lambda/proc that returns the prefix for newly generated tokens.
|
18
|
+
# Defaults to "ak_".
|
19
|
+
# Once set, do NOT change or all previously generated keys may become invalid!
|
20
|
+
# config.token_prefix = -> { "ak_" }
|
21
|
+
|
22
|
+
# The number of random bytes to generate for the token (before encoding).
|
23
|
+
# More bytes = more entropy = harder to guess.
|
24
|
+
# Default: 24 (generates ~32 Base58 chars or 48 hex chars)
|
25
|
+
# config.token_length = 32
|
26
|
+
|
27
|
+
# The encoding alphabet for the random part of the token.
|
28
|
+
# :base58 (recommended) - shorter, avoids ambiguous chars (0, O, I, l)
|
29
|
+
# :hex - standard hexadecimal encoding
|
30
|
+
# Default: :base58
|
31
|
+
# config.token_alphabet = :hex
|
32
|
+
|
33
|
+
# === Storage & Verification ===
|
34
|
+
|
35
|
+
# The hashing strategy used to store token digests in the database.
|
36
|
+
# :sha256 (recommended) - fast, performant, O(1) lookups, but less secure if database is compromised (salted with prefix only)
|
37
|
+
# :bcrypt - for security-critical tokens: includes salt, computationally expensive, can cause lags, 10x-50x slower than sha256
|
38
|
+
# Default: :sha256
|
39
|
+
# config.hash_strategy = :bcrypt
|
40
|
+
|
41
|
+
# === Optional Behaviors ===
|
42
|
+
|
43
|
+
# Global limit on the number of *active* keys an owner can have.
|
44
|
+
# Can be overridden by `max_keys` in the `has_api_keys` block.
|
45
|
+
# Set to nil for no global limit.
|
46
|
+
# Default: nil
|
47
|
+
# config.default_max_keys_per_owner = 10
|
48
|
+
|
49
|
+
# If true, requires a `name` when creating keys.
|
50
|
+
# Can be overridden by `require_name` in the `has_api_keys` block.
|
51
|
+
# Default: false
|
52
|
+
# config.require_key_name = true
|
53
|
+
|
54
|
+
# Automatically expire keys after a certain period from creation.
|
55
|
+
# Set to nil for no automatic expiration.
|
56
|
+
# Default: nil
|
57
|
+
# config.expire_after = 90.days
|
58
|
+
|
59
|
+
# Default scopes to assign to newly created keys if none are specified.
|
60
|
+
# Applies globally unless overridden by `has_api_keys` in the owner model.
|
61
|
+
# Default: []
|
62
|
+
# config.default_scopes = ["read"]
|
63
|
+
|
64
|
+
# === Performance ===
|
65
|
+
|
66
|
+
# Time-to-live (TTL) for caching ApiKey lookups.
|
67
|
+
# Higher values improve performance by reducing database lookups and
|
68
|
+
# expensive comparisons (like bcrypt), but increase the delay for changes
|
69
|
+
# (like revocation or expiration) to take effect for already cached keys.
|
70
|
+
# Set to 0 or nil to disable caching.
|
71
|
+
# Uses Rails.cache.
|
72
|
+
# Default: 5.seconds
|
73
|
+
# config.cache_ttl = 30.seconds # Higher TTL = higher risk of “revoked-but-still-valid” edge cases
|
74
|
+
|
75
|
+
# === Security ===
|
76
|
+
|
77
|
+
# If true, logs a warning if the gem is used over HTTP in production.
|
78
|
+
# Default: true
|
79
|
+
# config.https_only_production = true
|
80
|
+
|
81
|
+
# If true (and https_only_production is true), raises an error instead of
|
82
|
+
# just logging a warning when used over HTTP in production.
|
83
|
+
# Default: false
|
84
|
+
# config.https_strict_mode = true
|
85
|
+
|
86
|
+
# IMPORTANT: Usage Statistics & Background Jobs
|
87
|
+
# ---------------------------------------------
|
88
|
+
# The api_keys gem executes callbacks and updates the `last_used_at` timestamp on every successful authentication
|
89
|
+
# and optionally increments `requests_count` if `track_requests_count` is true.
|
90
|
+
# To avoid blocking the request cycle, these calls and updates are performed asynchronously
|
91
|
+
# using ActiveJob (`ApiKeys::Jobs::UpdateStatsJob` and `ApiKeys::Jobs::CallbacksJob`)
|
92
|
+
#
|
93
|
+
# *** For callbacks to be executed, and for reliable and performant usage statistics, you MUST configure a persistent
|
94
|
+
# ActiveJob backend adapter in your Rails app! (e.g., Sidekiq, GoodJob, SolidQueue, Resque, Delayed::Job). ***
|
95
|
+
#
|
96
|
+
# - Using the default :async adapter is NOT recommended for production as updates
|
97
|
+
# run in-process and may be lost if the application restarts unexpectedly.
|
98
|
+
# - Using the :inline adapter will perform updates synchronously within the request,
|
99
|
+
# negating the performance benefits and potentially slowing down responses.
|
100
|
+
#
|
101
|
+
# If you do not have a persistent background job system configured, callbacks won't fire and stats updates
|
102
|
+
# might be unreliable or impact performance. Consider disabling `track_requests_count` and avoid using callbacks
|
103
|
+
# if you cannot use a persistent backend and performance is critical.
|
104
|
+
|
105
|
+
# === Background Job Queues ===
|
106
|
+
|
107
|
+
# Configure the ActiveJob queue name for processing API key usage statistics.
|
108
|
+
# Default: :default
|
109
|
+
# config.stats_job_queue = :api_keys_stats
|
110
|
+
|
111
|
+
# Configure the ActiveJob queue name for processing asynchronous callbacks.
|
112
|
+
# Default: :default
|
113
|
+
# config.callbacks_job_queue = :api_keys_callbacks
|
114
|
+
|
115
|
+
# === Global Async Toggle ===
|
116
|
+
|
117
|
+
# Set to false to completely disable all background job enqueueing performed
|
118
|
+
# by this gem (stats updates and callbacks). If false, `last_used_at`,
|
119
|
+
# `requests_count`, and configured callbacks will NOT be processed.
|
120
|
+
# Useful if you handle these concerns externally or cannot use ActiveJob.
|
121
|
+
# Default: true
|
122
|
+
# config.enable_async_operations = false
|
123
|
+
|
124
|
+
# === Usage Statistics ===
|
125
|
+
|
126
|
+
# If true, automatically update `last_used_at` and increment `requests_count`
|
127
|
+
# on the ApiKey record upon successful authentication.
|
128
|
+
# Note: Incrementing counters frequently can impact DB performance.
|
129
|
+
# Default: false
|
130
|
+
# config.track_requests_count = true
|
131
|
+
|
132
|
+
# === Callbacks ===
|
133
|
+
|
134
|
+
# A lambda/proc to run *before* token extraction and verification.
|
135
|
+
# Receives the request object.
|
136
|
+
# Default: ->(request) { }
|
137
|
+
# config.before_authentication = ->(request) { Rails.logger.info "Authenticating request: #{request.uuid}" }
|
138
|
+
|
139
|
+
# A lambda/proc to run *after* authentication attempt (success or failure).
|
140
|
+
# Receives the ApiKeys::Services::Authenticator::Result object.
|
141
|
+
# Default: ->(result) { }
|
142
|
+
# config.after_authentication = ->(result) { MyAnalytics.track_auth(result) }
|
143
|
+
|
144
|
+
# === Engine UI Configuration ===
|
145
|
+
|
146
|
+
# The URL or path helper method (as a string) to link back to from the engine's UI.
|
147
|
+
# Useful when embedding the engine within a larger application context.
|
148
|
+
# Default: "/" (Root path)
|
149
|
+
# config.return_url = "/app/settings"
|
150
|
+
|
151
|
+
# The text displayed for the return link.
|
152
|
+
# Default: "‹ Home"
|
153
|
+
# config.return_text = "‹ Back to Settings"
|
154
|
+
|
155
|
+
# === Debugging ===
|
156
|
+
|
157
|
+
# Enable verbose logging for debugging purposes.
|
158
|
+
# Default: false
|
159
|
+
# config.debug_logging = true
|
160
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_keys
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- rameerez
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-04-30 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: rails
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '6.1'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '6.1'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: activerecord
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '6.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '6.0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: activesupport
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '6.0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '6.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: base58
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.2'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.2'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: bcrypt
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.1'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.1'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: bundler
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '2.0'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '2.0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: rake
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '13.0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '13.0'
|
110
|
+
description: Add secure, production-ready API key authentication to your Rails app
|
111
|
+
in minutes. Handles key generation, hashing, expiration, revocation, per-key scopes;
|
112
|
+
plus a drop-in dashboard for your users to self-issue and manage their own API keys.
|
113
|
+
email:
|
114
|
+
- rubygems@rameerez.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- CHANGELOG.md
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- api_keys_dashboard.webp
|
124
|
+
- api_keys_permissions.webp
|
125
|
+
- api_keys_token.webp
|
126
|
+
- app/controllers/api_keys/application_controller.rb
|
127
|
+
- app/controllers/api_keys/keys_controller.rb
|
128
|
+
- app/controllers/api_keys/security_controller.rb
|
129
|
+
- app/views/api_keys/keys/_form.html.erb
|
130
|
+
- app/views/api_keys/keys/_key_row.html.erb
|
131
|
+
- app/views/api_keys/keys/_keys_table.html.erb
|
132
|
+
- app/views/api_keys/keys/_show_token.html.erb
|
133
|
+
- app/views/api_keys/keys/edit.html.erb
|
134
|
+
- app/views/api_keys/keys/index.html.erb
|
135
|
+
- app/views/api_keys/keys/new.html.erb
|
136
|
+
- app/views/api_keys/keys/show.html.erb
|
137
|
+
- app/views/api_keys/security/best_practices.html.erb
|
138
|
+
- app/views/layouts/api_keys/application.html.erb
|
139
|
+
- config/routes.rb
|
140
|
+
- lib/api_keys.rb
|
141
|
+
- lib/api_keys/authentication.rb
|
142
|
+
- lib/api_keys/configuration.rb
|
143
|
+
- lib/api_keys/controller.rb
|
144
|
+
- lib/api_keys/engine.rb
|
145
|
+
- lib/api_keys/jobs/callbacks_job.rb
|
146
|
+
- lib/api_keys/jobs/update_stats_job.rb
|
147
|
+
- lib/api_keys/logging.rb
|
148
|
+
- lib/api_keys/models/api_key.rb
|
149
|
+
- lib/api_keys/models/concerns/has_api_keys.rb
|
150
|
+
- lib/api_keys/services/authenticator.rb
|
151
|
+
- lib/api_keys/services/digestor.rb
|
152
|
+
- lib/api_keys/services/token_generator.rb
|
153
|
+
- lib/api_keys/tenant_resolution.rb
|
154
|
+
- lib/api_keys/version.rb
|
155
|
+
- lib/generators/api_keys/install_generator.rb
|
156
|
+
- lib/generators/api_keys/templates/create_api_keys_table.rb.erb
|
157
|
+
- lib/generators/api_keys/templates/initializer.rb
|
158
|
+
homepage: https://github.com/rameerez/api_keys
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
metadata:
|
162
|
+
allowed_push_host: https://rubygems.org
|
163
|
+
homepage_uri: https://apikeys.rameerez.com
|
164
|
+
source_code_uri: https://github.com/rameerez/api_keys
|
165
|
+
changelog_uri: https://github.com/rameerez/api_keys/blob/main/CHANGELOG.md
|
166
|
+
rubygems_mfa_required: 'true'
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 3.1.0
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubygems_version: 3.6.2
|
182
|
+
specification_version: 4
|
183
|
+
summary: Gate your Rails API with secure, self-serve API keys in minutes
|
184
|
+
test_files: []
|