grape_oauth2 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +18 -0
- data/.travis.yml +42 -0
- data/Gemfile +23 -0
- data/README.md +820 -0
- data/Rakefile +11 -0
- data/gemfiles/active_record.rb +25 -0
- data/gemfiles/mongoid.rb +14 -0
- data/gemfiles/sequel.rb +24 -0
- data/grape_oauth2.gemspec +27 -0
- data/grape_oauth2.png +0 -0
- data/lib/grape_oauth2.rb +129 -0
- data/lib/grape_oauth2/configuration.rb +143 -0
- data/lib/grape_oauth2/configuration/class_accessors.rb +36 -0
- data/lib/grape_oauth2/configuration/validation.rb +71 -0
- data/lib/grape_oauth2/endpoints/authorize.rb +34 -0
- data/lib/grape_oauth2/endpoints/token.rb +72 -0
- data/lib/grape_oauth2/gem_version.rb +24 -0
- data/lib/grape_oauth2/generators/authorization.rb +44 -0
- data/lib/grape_oauth2/generators/base.rb +26 -0
- data/lib/grape_oauth2/generators/token.rb +62 -0
- data/lib/grape_oauth2/helpers/access_token_helpers.rb +54 -0
- data/lib/grape_oauth2/helpers/oauth_params.rb +41 -0
- data/lib/grape_oauth2/mixins/active_record/access_grant.rb +47 -0
- data/lib/grape_oauth2/mixins/active_record/access_token.rb +75 -0
- data/lib/grape_oauth2/mixins/active_record/client.rb +35 -0
- data/lib/grape_oauth2/mixins/mongoid/access_grant.rb +58 -0
- data/lib/grape_oauth2/mixins/mongoid/access_token.rb +88 -0
- data/lib/grape_oauth2/mixins/mongoid/client.rb +41 -0
- data/lib/grape_oauth2/mixins/sequel/access_grant.rb +68 -0
- data/lib/grape_oauth2/mixins/sequel/access_token.rb +86 -0
- data/lib/grape_oauth2/mixins/sequel/client.rb +46 -0
- data/lib/grape_oauth2/responses/authorization.rb +10 -0
- data/lib/grape_oauth2/responses/base.rb +56 -0
- data/lib/grape_oauth2/responses/token.rb +10 -0
- data/lib/grape_oauth2/scopes.rb +74 -0
- data/lib/grape_oauth2/strategies/authorization_code.rb +38 -0
- data/lib/grape_oauth2/strategies/base.rb +47 -0
- data/lib/grape_oauth2/strategies/client_credentials.rb +20 -0
- data/lib/grape_oauth2/strategies/password.rb +22 -0
- data/lib/grape_oauth2/strategies/refresh_token.rb +47 -0
- data/lib/grape_oauth2/unique_token.rb +20 -0
- data/lib/grape_oauth2/version.rb +14 -0
- data/spec/configuration/config_spec.rb +231 -0
- data/spec/configuration/version_spec.rb +12 -0
- data/spec/dummy/endpoints/custom_authorization.rb +25 -0
- data/spec/dummy/endpoints/custom_token.rb +35 -0
- data/spec/dummy/endpoints/status.rb +25 -0
- data/spec/dummy/grape_oauth2_config.rb +11 -0
- data/spec/dummy/orm/active_record/app/config/db.rb +7 -0
- data/spec/dummy/orm/active_record/app/models/access_code.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/access_token.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/application.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/application_record.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/user.rb +10 -0
- data/spec/dummy/orm/active_record/app/twitter.rb +36 -0
- data/spec/dummy/orm/active_record/config.ru +7 -0
- data/spec/dummy/orm/active_record/db/schema.rb +53 -0
- data/spec/dummy/orm/mongoid/app/config/db.rb +6 -0
- data/spec/dummy/orm/mongoid/app/config/mongoid.yml +21 -0
- data/spec/dummy/orm/mongoid/app/models/access_code.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/access_token.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/application.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/user.rb +11 -0
- data/spec/dummy/orm/mongoid/app/twitter.rb +34 -0
- data/spec/dummy/orm/mongoid/config.ru +5 -0
- data/spec/dummy/orm/sequel/app/config/db.rb +1 -0
- data/spec/dummy/orm/sequel/app/models/access_code.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/access_token.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/application.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/application_record.rb +2 -0
- data/spec/dummy/orm/sequel/app/models/user.rb +11 -0
- data/spec/dummy/orm/sequel/app/twitter.rb +47 -0
- data/spec/dummy/orm/sequel/config.ru +5 -0
- data/spec/dummy/orm/sequel/db/schema.rb +50 -0
- data/spec/lib/scopes_spec.rb +50 -0
- data/spec/mixins/active_record/access_token_spec.rb +185 -0
- data/spec/mixins/active_record/client_spec.rb +95 -0
- data/spec/mixins/mongoid/access_token_spec.rb +185 -0
- data/spec/mixins/mongoid/client_spec.rb +95 -0
- data/spec/mixins/sequel/access_token_spec.rb +185 -0
- data/spec/mixins/sequel/client_spec.rb +96 -0
- data/spec/requests/flows/authorization_code_spec.rb +67 -0
- data/spec/requests/flows/client_credentials_spec.rb +101 -0
- data/spec/requests/flows/password_spec.rb +210 -0
- data/spec/requests/flows/refresh_token_spec.rb +222 -0
- data/spec/requests/flows/revoke_token_spec.rb +103 -0
- data/spec/requests/protected_resources_spec.rb +64 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/api_helper.rb +11 -0
- metadata +257 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
# Grape::OAuth2 endpoints namespace
|
4
|
+
module Endpoints
|
5
|
+
# OAuth2 Grape authorization endpoint.
|
6
|
+
class Authorize < ::Grape::API
|
7
|
+
helpers Grape::OAuth2::Helpers::OAuthParams
|
8
|
+
|
9
|
+
namespace :oauth do
|
10
|
+
desc 'OAuth 2.0 Authorization Endpoint'
|
11
|
+
|
12
|
+
params do
|
13
|
+
use :oauth_authorization_params
|
14
|
+
end
|
15
|
+
|
16
|
+
post :authorize do
|
17
|
+
response = Grape::OAuth2::Generators::Authorization.generate_for(env)
|
18
|
+
|
19
|
+
# Status
|
20
|
+
status response.status
|
21
|
+
|
22
|
+
# Headers
|
23
|
+
response.headers.each do |key, value|
|
24
|
+
header key, value
|
25
|
+
end
|
26
|
+
|
27
|
+
# Body
|
28
|
+
body response.body
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
# Grape::OAuth2 endpoints namespace
|
4
|
+
module Endpoints
|
5
|
+
# OAuth2 Grape token endpoint.
|
6
|
+
class Token < ::Grape::API
|
7
|
+
helpers Grape::OAuth2::Helpers::OAuthParams
|
8
|
+
|
9
|
+
namespace :oauth do
|
10
|
+
# @see https://tools.ietf.org/html/rfc6749#section-3.2
|
11
|
+
#
|
12
|
+
desc 'OAuth 2.0 Token Endpoint'
|
13
|
+
|
14
|
+
params do
|
15
|
+
use :oauth_token_params
|
16
|
+
end
|
17
|
+
|
18
|
+
post :token do
|
19
|
+
token_response = Grape::OAuth2::Generators::Token.generate_for(env)
|
20
|
+
|
21
|
+
# Status
|
22
|
+
status token_response.status
|
23
|
+
|
24
|
+
# Headers
|
25
|
+
token_response.headers.each do |key, value|
|
26
|
+
header key, value
|
27
|
+
end
|
28
|
+
|
29
|
+
# Body
|
30
|
+
body token_response.body
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'OAuth 2.0 Token Revocation'
|
34
|
+
|
35
|
+
params do
|
36
|
+
use :oauth_token_revocation_params
|
37
|
+
end
|
38
|
+
|
39
|
+
post :revoke do
|
40
|
+
access_token = Grape::OAuth2.config.access_token_class.authenticate(params[:token],
|
41
|
+
type: params[:token_type_hint])
|
42
|
+
|
43
|
+
if access_token
|
44
|
+
if access_token.client
|
45
|
+
request = Rack::OAuth2::Server::Token::Request.new(env)
|
46
|
+
|
47
|
+
# The authorization server, if applicable, first authenticates the client
|
48
|
+
# and checks its ownership of the provided token.
|
49
|
+
client = Grape::OAuth2::Strategies::Base.authenticate_client(request)
|
50
|
+
request.invalid_client! if client.nil?
|
51
|
+
|
52
|
+
access_token.revoke! if client && client == access_token.client
|
53
|
+
else
|
54
|
+
# Access token is public
|
55
|
+
access_token.revoke!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# The authorization server responds with HTTP status code 200 if the token
|
60
|
+
# has been revoked successfully or if the client submitted an invalid
|
61
|
+
# token.
|
62
|
+
#
|
63
|
+
# @see https://tools.ietf.org/html/rfc7009#section-2.2 Revocation Response
|
64
|
+
#
|
65
|
+
status 200
|
66
|
+
{}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
# Grape::OAuth2 version.
|
4
|
+
# @return [Gem::Version] version of the gem
|
5
|
+
#
|
6
|
+
def self.gem_version
|
7
|
+
Gem::Version.new VERSION::STRING
|
8
|
+
end
|
9
|
+
|
10
|
+
# Grape::OAuth2 semantic versioning module.
|
11
|
+
# Contains detailed info about gem version.
|
12
|
+
module VERSION
|
13
|
+
# Major version of the gem
|
14
|
+
MAJOR = 0
|
15
|
+
# Minor version of the gem
|
16
|
+
MINOR = 1
|
17
|
+
# Tiny version of the gem
|
18
|
+
TINY = 1
|
19
|
+
|
20
|
+
# Full gem version string
|
21
|
+
STRING = [MAJOR, MINOR, TINY].compact.join('.')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Generators
|
4
|
+
# OAuth2 Authorization generator class.
|
5
|
+
# Processes the request and builds the response.
|
6
|
+
class Authorization < Base
|
7
|
+
class << self
|
8
|
+
# Generates Authorization Response based on the request.
|
9
|
+
#
|
10
|
+
# @return [Grape::OAuth2::Responses::Authorization] response
|
11
|
+
#
|
12
|
+
def generate_for(env, &_block)
|
13
|
+
authorization = Rack::OAuth2::Server::Authorize.new do |request, response|
|
14
|
+
if block_given?
|
15
|
+
yield request, response
|
16
|
+
else
|
17
|
+
execute_default(request, response)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Grape::OAuth2::Responses::Authorization.new(authorization.call(env))
|
22
|
+
rescue Rack::OAuth2::Server::Authorize::BadRequest => error
|
23
|
+
error_response(error)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def error_response(error)
|
29
|
+
response = Rack::Response.new
|
30
|
+
response.status = error.status
|
31
|
+
response.header['Content-Type'] = 'application/json'
|
32
|
+
response.write(JSON.dump(Rack::OAuth2::Util.compact_hash(error.protocol_params)))
|
33
|
+
|
34
|
+
Grape::OAuth2::Responses::Authorization.new(response.finish)
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute_default(request, response)
|
38
|
+
Grape::OAuth2::Strategies::AuthorizationCode.process(request, response)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Generators
|
4
|
+
# Base class for Grape::OAuth2 generators.
|
5
|
+
# Grape::OAuth2 generators processes the requests and
|
6
|
+
# generates responses with Access Token or Authorization Code.
|
7
|
+
class Base
|
8
|
+
class << self
|
9
|
+
# Allowed grant types from the Grape::OAuth2 configuration.
|
10
|
+
#
|
11
|
+
# @return [Array]
|
12
|
+
# allowed grant types
|
13
|
+
#
|
14
|
+
def allowed_grants
|
15
|
+
config.allowed_grant_types
|
16
|
+
end
|
17
|
+
|
18
|
+
# Short getter for Grape::OAuth2 configuration.
|
19
|
+
def config
|
20
|
+
Grape::OAuth2.config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Generators
|
4
|
+
# OAuth2 Token generator class.
|
5
|
+
# Processes the request by required Grant Type and builds the response.
|
6
|
+
class Token < Base
|
7
|
+
# Grant type => OAuth2 strategy class
|
8
|
+
STRATEGY_CLASSES = {
|
9
|
+
password: Grape::OAuth2::Strategies::Password,
|
10
|
+
client_credentials: Grape::OAuth2::Strategies::ClientCredentials,
|
11
|
+
refresh_token: Grape::OAuth2::Strategies::RefreshToken
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Generates Token Response based on the request.
|
16
|
+
#
|
17
|
+
# @return [Grape::OAuth2::Responses::Token] response
|
18
|
+
#
|
19
|
+
def generate_for(env, &_block)
|
20
|
+
token = Rack::OAuth2::Server::Token.new do |request, response|
|
21
|
+
request.unsupported_grant_type! unless allowed_grants.include?(request.grant_type.to_s)
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
yield request, response
|
25
|
+
else
|
26
|
+
execute_default(request, response)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Grape::OAuth2::Responses::Token.new(token.call(env))
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
# Runs default Grape::OAuth2 functionality for Token endpoint.
|
36
|
+
# In common it authenticates client (or/and any other objects) and
|
37
|
+
# grants the Access Token or Auth Code.
|
38
|
+
#
|
39
|
+
# @param request [Rack::Request] request object
|
40
|
+
# @param response [Rack::Response] response object
|
41
|
+
#
|
42
|
+
def execute_default(request, response)
|
43
|
+
strategy = find_strategy(request.grant_type) || request.invalid_grant!
|
44
|
+
response.access_token = strategy.process(request)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns Grape::OAuth2 strategy class by Grant Type.
|
48
|
+
#
|
49
|
+
# @param grant_type [Symbol]
|
50
|
+
# grant type value
|
51
|
+
#
|
52
|
+
# @return [Password, ClientCredentials, RefreshToken]
|
53
|
+
# strategy class
|
54
|
+
#
|
55
|
+
def find_strategy(grant_type)
|
56
|
+
STRATEGY_CLASSES[grant_type]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Helpers
|
4
|
+
# Set of Grape OAuth2 helpers.
|
5
|
+
module AccessTokenHelpers
|
6
|
+
extend ::Grape::API::Helpers
|
7
|
+
|
8
|
+
# Adds OAuth2 Access Token protection for Grape routes.
|
9
|
+
#
|
10
|
+
# @param scopes [Array]
|
11
|
+
# set of scopes required to access the endpoint
|
12
|
+
#
|
13
|
+
# @raise [Rack::OAuth2::Server::Resource::Bearer::Unauthorized]
|
14
|
+
# invalid Access Token value
|
15
|
+
# @raise [Rack::OAuth2::Server::Resource::Bearer::Forbidden]
|
16
|
+
# Access Token expired, revoked or does't have required scopes
|
17
|
+
#
|
18
|
+
def access_token_required!(*scopes)
|
19
|
+
endpoint_scopes = env['api.endpoint'].options[:route_options][:scopes]
|
20
|
+
required_scopes = endpoint_scopes.presence || scopes
|
21
|
+
|
22
|
+
raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized if current_access_token.nil?
|
23
|
+
raise Rack::OAuth2::Server::Resource::Bearer::Forbidden unless valid_access_token?(required_scopes)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns Resource Owner from the Access Token
|
27
|
+
# found by access_token value passed with the request.
|
28
|
+
def current_resource_owner
|
29
|
+
@_current_resource_owner ||= current_access_token.resource_owner
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns Access Token instance found by
|
33
|
+
# access_token value passed with the request.
|
34
|
+
def current_access_token
|
35
|
+
@_current_access_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Validate current access token not to be expired or revoked
|
41
|
+
# and has all the requested scopes.
|
42
|
+
#
|
43
|
+
# @return [Boolean]
|
44
|
+
# true if current Access Token not expired, not revoked and scopes match
|
45
|
+
# false in other cases.
|
46
|
+
#
|
47
|
+
def valid_access_token?(scopes)
|
48
|
+
!current_access_token.revoked? && !current_access_token.expired? &&
|
49
|
+
Grape::OAuth2.config.scopes_validator.new(scopes).valid_for?(current_access_token)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Helpers
|
4
|
+
# Grape Helper object for OAuth2 requests params.
|
5
|
+
# Used fin default Grape::OAuth2 gem endpoints and can be used
|
6
|
+
# for custom one.
|
7
|
+
module OAuthParams
|
8
|
+
extend ::Grape::API::Helpers
|
9
|
+
|
10
|
+
# Params are optional in order to process them correctly in accordance
|
11
|
+
# with the RFC 6749 (invalid_client, unsupported_grant_type, etc.)
|
12
|
+
params :oauth_token_params do
|
13
|
+
optional :grant_type, type: String, desc: 'Grant type'
|
14
|
+
optional :client_id, type: String, desc: 'Client ID'
|
15
|
+
optional :client_secret, type: String, desc: 'Client secret'
|
16
|
+
optional :refresh_token, type: String, desc: 'Refresh Token'
|
17
|
+
end
|
18
|
+
|
19
|
+
# Params for authorization request.
|
20
|
+
# @see https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1.1 Authorization Request
|
21
|
+
params :oauth_authorization_params do
|
22
|
+
optional :response_type, type: String, desc: 'Response type'
|
23
|
+
optional :client_id, type: String, desc: 'Client ID'
|
24
|
+
optional :redirect_uri, type: String, desc: 'Redirect URI'
|
25
|
+
optional :scope, type: String, desc: 'Authorization scopes'
|
26
|
+
optional :state, type: String, desc: 'State'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Params for token revocation.
|
30
|
+
# @see https://tools.ietf.org/html/rfc7009#section-2.1 OAuth 2.0 Token Revocation
|
31
|
+
params :oauth_token_revocation_params do
|
32
|
+
requires :token, type: String, desc: 'The token that the client wants to get revoked'
|
33
|
+
optional :token_type_hint, type: String,
|
34
|
+
values: %w(access_token refresh_token),
|
35
|
+
default: 'access_token',
|
36
|
+
desc: 'A hint about the type of the token submitted for revocation'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module ActiveRecord
|
4
|
+
# Grape::OAuth2 Authorization Grant role mixin for ActiveRecord.
|
5
|
+
# Includes all the required API, associations, validations and callbacks.
|
6
|
+
module AccessGrant
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
belongs_to :client, class_name: Grape::OAuth2.config.client_class_name,
|
11
|
+
foreign_key: :client_id
|
12
|
+
|
13
|
+
belongs_to :resource_owner, class_name: Grape::OAuth2.config.resource_owner_class_name,
|
14
|
+
foreign_key: :resource_owner_id
|
15
|
+
|
16
|
+
# resource_owner_id - required!
|
17
|
+
validates :client_id, :redirect_uri, presence: true
|
18
|
+
validates :token, presence: true, uniqueness: true
|
19
|
+
|
20
|
+
before_validation :generate_token, on: :create
|
21
|
+
before_validation :setup_expiration, on: :create
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def create_for(client, resource_owner, redirect_uri, scopes = nil)
|
25
|
+
create(
|
26
|
+
client_id: client.id,
|
27
|
+
resource_owner_id: resource_owner && resource_owner.id,
|
28
|
+
redirect_uri: redirect_uri,
|
29
|
+
scopes: scopes.to_s
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def generate_token
|
37
|
+
self.token = Grape::OAuth2.config.token_generator.generate(attributes)
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_expiration
|
41
|
+
self.expires_at = Time.now.utc + Grape::OAuth2.config.authorization_code_lifetime if expires_at.nil?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module ActiveRecord
|
4
|
+
# Grape::OAuth2 Access Token role mixin for ActiveRecord.
|
5
|
+
# Includes all the required API, associations, validations and callbacks.
|
6
|
+
module AccessToken
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
belongs_to :client, class_name: Grape::OAuth2.config.client_class_name,
|
11
|
+
foreign_key: :client_id
|
12
|
+
|
13
|
+
belongs_to :resource_owner, class_name: Grape::OAuth2.config.resource_owner_class_name,
|
14
|
+
foreign_key: :resource_owner_id
|
15
|
+
|
16
|
+
validates :token, presence: true, uniqueness: true
|
17
|
+
|
18
|
+
before_validation :setup_expiration, on: :create
|
19
|
+
before_validation :generate_tokens, on: :create
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def create_for(client, resource_owner, scopes = nil)
|
23
|
+
create(
|
24
|
+
client: client,
|
25
|
+
resource_owner: resource_owner,
|
26
|
+
scopes: scopes.to_s
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def authenticate(token, type: :access_token)
|
31
|
+
if type && type.to_sym == :refresh_token
|
32
|
+
find_by(refresh_token: token.to_s)
|
33
|
+
else
|
34
|
+
find_by(token: token.to_s)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def expired?
|
40
|
+
!expires_at.nil? && Time.now.utc > expires_at
|
41
|
+
end
|
42
|
+
|
43
|
+
def revoked?
|
44
|
+
!revoked_at.nil? && revoked_at <= Time.now.utc
|
45
|
+
end
|
46
|
+
|
47
|
+
def revoke!(revoked_at = Time.now)
|
48
|
+
update_column :revoked_at, revoked_at.utc
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_bearer_token
|
52
|
+
{
|
53
|
+
access_token: token,
|
54
|
+
expires_in: expires_at && Grape::OAuth2.config.access_token_lifetime.to_i,
|
55
|
+
refresh_token: refresh_token,
|
56
|
+
scope: scopes
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def generate_tokens
|
63
|
+
self.token = Grape::OAuth2.config.token_generator.generate(attributes) if token.blank?
|
64
|
+
self.refresh_token = Grape::OAuth2::UniqueToken.generate if Grape::OAuth2.config.issue_refresh_token
|
65
|
+
end
|
66
|
+
|
67
|
+
def setup_expiration
|
68
|
+
expires_in = Grape::OAuth2.config.access_token_lifetime
|
69
|
+
self.expires_at = Time.now + expires_in if expires_at.nil? && !expires_in.nil?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|