Skip to content

Commit

Permalink
Refactor grant handling with strategy pattern
Browse files Browse the repository at this point in the history
Implemented a strategy pattern to generalize grant handling in the Authly module, enhancing flexibility and maintainability. Introduced an abstract `GrantStrategy` module and encapsulated specific grant logic into dedicated classes, now adhering to the strategy interface. This approach reduces redundancy by delegating authorization checks to respective strategy implementations. Additionally, a factory method was introduced for strategy creation based on grant type, streamlining grant instantiation and ensuring unsupported grant types are properly handled. This refactor aims to improve system design coherence and extensibility.
  • Loading branch information
eliasjpr committed Oct 9, 2024
1 parent 92ee334 commit 91e97e7
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 49 deletions.
95 changes: 46 additions & 49 deletions src/authly/grant.cr
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
module Authly
module GrantStrategy
abstract def authorized? : Bool
end

class GrantFactory
def self.create(grant_type : String, **args) : GrantStrategy
case grant_type
when "authorization_code"
AuthorizationCode.new(
args["client_id"],
args["client_secret"],
args.fetch("redirect_uri", ""),
args.fetch("challenge", ""),
args.fetch("method", ""),
args.fetch("verifier", "")
)
when "client_credentials"
ClientCredentials.new(args["client_id"], args["client_secret"])
when "password"
Password.new(
args["client_id"],
args["client_secret"],
args.fetch("username", ""),
args.fetch("password", "")
)
when "refresh_token"
RefreshToken.new(
args["client_id"],
args["client_secret"],
args.fetch("refresh_token", "")
)
else
raise Error.unsupported_grant_type
end
end
end

class Grant
getter grant_type : String,
client_id : String,
client_secret : String,
username : String,
password : String,
redirect_uri : String,
code : String,
verifier : String,
refresh_token : String
@grant_strategy : GrantStrategy
@code : String

def initialize(@grant_type,
@client_id = "",
@client_secret = "",
@username = "",
@password = "",
@redirect_uri = "",
@code = "",
@verifier = "",
@refresh_token = "")
def initialize(grant_type : String, **args)
@grant_strategy = GrantFactory.create(grant_type, **args)
@code = args.fetch("code", "")
end

def token : AccessToken
Expand All @@ -27,42 +51,15 @@ module Authly
end

def authorized?
grant = case grant_type
when "authorization_code" then authorization_code
when "client_credentials" then client_credentials
when "password" then password_grant
when "refresh_token" then refresh_token_grant
else raise Error.unsupported_grant_type
end

grant.authorized?
end

def authorization_code
AuthorizationCode.new(
client_id,
client_secret,
redirect_uri,
auth_code["challenge"].as_s,
auth_code["method"].as_s,
verifier
)
end

def client_credentials
ClientCredentials.new(client_id, client_secret)
end

def password_grant
Password.new(client_id, client_secret, username, password)
@grant_strategy.authorized?
end

def refresh_token_grant
RefreshToken.new(client_id, client_secret, refresh_token)
end

private def access_token
AccessToken.new(client_id, scope, generate_id_token)
AccessToken.new(@grant_strategy.client_id, scope, generate_id_token)
end

private def generate_id_token
Expand All @@ -72,11 +69,11 @@ module Authly
end

private def auth_code
Authly.jwt_decode(code).first
Authly.jwt_decode(@code).first
end

private def scope : String
return "" if code.empty?
return "" if @code.empty?
auth_code["scope"].as_s
end
end
Expand Down
2 changes: 2 additions & 0 deletions src/authly/grants/authorization_code.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ require "uri"

module Authly
class AuthorizationCode
include GrantStrategy

getter client_id : String,
client_secret : String,
redirect_uri : String,
Expand Down
1 change: 1 addition & 0 deletions src/authly/grants/client_credentials.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Authly
class ClientCredentials
include GrantStrategy
getter client_id : String, client_secret : String

def initialize(@client_id, @client_secret)
Expand Down
1 change: 1 addition & 0 deletions src/authly/grants/password.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Authly
class Password
include GrantStrategy
getter client_id : String,
client_secret : String,
username : String,
Expand Down
1 change: 1 addition & 0 deletions src/authly/grants/refresh_token.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Authly
class RefreshToken
include GrantStrategy
getter client_id : String,
client_secret : String,
refresh_token : String
Expand Down

0 comments on commit 91e97e7

Please sign in to comment.