hanko-ruby 0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 73c45486ef99cb5a9cabbdfaa4fa4900eb336f5cd96f9699c0f8e5cbff32d7f1
4
+ data.tar.gz: 46eacc55fd29afc575bd7bb4c829ab878c84c4d73d9e811087b124bcbbede268
5
+ SHA512:
6
+ metadata.gz: d929d9d4647418c5e4ff0aa947cedac5dced6b50cb26bb22c4746c0a09489cee4071a18ee748becfaea22d991a852ed9ee3a3686904968910ad1f89e1fca6f67
7
+ data.tar.gz: ef0ff26d1c4febd94375452e482e79b2758681bd1db83780f8ec46da11bb5a91e3d701f7d4be88450ffd8a5b0c241293ec539ceccf239f11bd27a2bb19173c3a
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for querying audit logs.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class AuditLogs < BaseResource
9
+ # Initialize the audit logs resource.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @return [AuditLogs] a new AuditLogs instance
13
+ def initialize(connection)
14
+ super(connection, "/audit_logs")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing a user's email addresses.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class Emails < BaseResource
9
+ # Initialize the emails resource scoped to a user.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @param user_base_path [String] the base path for the parent user (e.g. "/users/:id")
13
+ # @return [Emails] a new Emails instance
14
+ def initialize(connection, user_base_path)
15
+ super(connection, "#{user_base_path}/emails")
16
+ @connection = connection
17
+ end
18
+
19
+ # Set an email address as the primary email for the user.
20
+ #
21
+ # @param email_id [String] the unique identifier of the email to make primary
22
+ # @return [Resource] the updated email resource
23
+ def set_primary(email_id)
24
+ response = @connection.post("#{@base_path}/#{email_id}/set_primary")
25
+ parse_resource(response.body)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing a user's metadata.
7
+ class Metadata
8
+ # Initialize the metadata resource scoped to a user.
9
+ #
10
+ # @param connection [Hanko::Connection] the HTTP connection to use
11
+ # @param user_base_path [String] the base path for the parent user (e.g. "/users/:id")
12
+ # @return [Metadata] a new Metadata instance
13
+ def initialize(connection, user_base_path)
14
+ @connection = connection
15
+ @base_path = "#{user_base_path}/metadata"
16
+ end
17
+
18
+ # Fetch the user's metadata.
19
+ #
20
+ # @return [Resource] the metadata resource
21
+ def get
22
+ response = @connection.get(@base_path)
23
+ Resource.new(JSON.parse(response.body))
24
+ end
25
+
26
+ # Update the user's metadata via PATCH.
27
+ #
28
+ # @param params [Hash] the metadata attributes to update
29
+ # @return [Resource] the updated metadata resource
30
+ def update(**params)
31
+ response = @connection.patch(@base_path, params)
32
+ Resource.new(JSON.parse(response.body))
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing a user's password.
7
+ class Passwords
8
+ # Initialize the passwords resource scoped to a user.
9
+ #
10
+ # @param connection [Hanko::Connection] the HTTP connection to use
11
+ # @param user_base_path [String] the base path for the parent user (e.g. "/users/:id")
12
+ # @return [Passwords] a new Passwords instance
13
+ def initialize(connection, user_base_path)
14
+ @connection = connection
15
+ @base_path = "#{user_base_path}/password"
16
+ end
17
+
18
+ # Create a password for the user.
19
+ #
20
+ # @param params [Hash] the password attributes
21
+ # @return [Resource] the created password resource
22
+ def create(**params)
23
+ response = @connection.post(@base_path, params)
24
+ Resource.new(JSON.parse(response.body))
25
+ end
26
+
27
+ # Fetch the user's password resource.
28
+ #
29
+ # @return [Resource] the password resource
30
+ def get
31
+ response = @connection.get(@base_path)
32
+ Resource.new(JSON.parse(response.body))
33
+ end
34
+
35
+ # Update the user's password.
36
+ #
37
+ # @param params [Hash] the password attributes to update
38
+ # @return [Resource] the updated password resource
39
+ def update(**params)
40
+ response = @connection.put(@base_path, params)
41
+ Resource.new(JSON.parse(response.body))
42
+ end
43
+
44
+ # Delete the user's password.
45
+ #
46
+ # @return [Boolean] true if deletion was successful
47
+ def delete
48
+ @connection.delete(@base_path)
49
+ true
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing a user's sessions.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class Sessions < BaseResource
9
+ # Initialize the sessions resource scoped to a user.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @param user_base_path [String] the base path for the parent user (e.g. "/users/:id")
13
+ # @return [Sessions] a new Sessions instance
14
+ def initialize(connection, user_base_path)
15
+ super(connection, "#{user_base_path}/sessions")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing users.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class Users < BaseResource
9
+ # Initialize the users resource.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @return [Users] a new Users instance
13
+ def initialize(connection)
14
+ super(connection, "/users")
15
+ @connection = connection
16
+ end
17
+
18
+ # Return a user-scoped context for accessing sub-resources.
19
+ #
20
+ # @param user_id [String] the unique identifier of the user
21
+ # @return [UserContext] a context scoped to the given user
22
+ def call(user_id)
23
+ UserContext.new(@connection, user_id)
24
+ end
25
+
26
+ # Provides access to sub-resources scoped to a specific user.
27
+ class UserContext
28
+ # Initialize a user-scoped context.
29
+ #
30
+ # @param connection [Hanko::Connection] the HTTP connection to use
31
+ # @param user_id [String] the unique identifier of the user
32
+ # @return [UserContext] a new UserContext instance
33
+ def initialize(connection, user_id)
34
+ @connection = connection
35
+ @user_id = user_id
36
+ @base_path = "/users/#{user_id}"
37
+ end
38
+
39
+ # Access the emails sub-resource for this user.
40
+ #
41
+ # @return [Emails] the emails resource scoped to this user
42
+ def emails
43
+ Emails.new(@connection, @base_path)
44
+ end
45
+
46
+ # Access the passwords sub-resource for this user.
47
+ #
48
+ # @return [Passwords] the passwords resource scoped to this user
49
+ def passwords
50
+ Passwords.new(@connection, @base_path)
51
+ end
52
+
53
+ # Access the sessions sub-resource for this user.
54
+ #
55
+ # @return [Sessions] the sessions resource scoped to this user
56
+ def sessions
57
+ Sessions.new(@connection, @base_path)
58
+ end
59
+
60
+ # Access the WebAuthn credentials sub-resource for this user.
61
+ #
62
+ # @return [WebauthnCredentials] the WebAuthn credentials resource scoped to this user
63
+ def webauthn_credentials
64
+ WebauthnCredentials.new(@connection, @base_path)
65
+ end
66
+
67
+ # Access the metadata sub-resource for this user.
68
+ #
69
+ # @return [Metadata] the metadata resource scoped to this user
70
+ def metadata
71
+ Metadata.new(@connection, @base_path)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing a user's WebAuthn credentials.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class WebauthnCredentials < BaseResource
9
+ # Initialize the WebAuthn credentials resource scoped to a user.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @param user_base_path [String] the base path for the parent user (e.g. "/users/:id")
13
+ # @return [WebauthnCredentials] a new WebauthnCredentials instance
14
+ def initialize(connection, user_base_path)
15
+ super(connection, "#{user_base_path}/webauthn_credentials")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Admin
6
+ # Admin resource for managing webhooks.
7
+ # Inherits list, get, create, update, delete from {BaseResource}.
8
+ class Webhooks < BaseResource
9
+ # Initialize the webhooks resource.
10
+ #
11
+ # @param connection [Hanko::Connection] the HTTP connection to use
12
+ # @return [Webhooks] a new Webhooks instance
13
+ def initialize(connection)
14
+ super(connection, "/webhooks")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "admin/users"
4
+ require_relative "admin/emails"
5
+ require_relative "admin/passwords"
6
+ require_relative "admin/sessions"
7
+ require_relative "admin/webauthn_credentials"
8
+ require_relative "admin/metadata"
9
+ require_relative "admin/webhooks"
10
+ require_relative "admin/audit_logs"
11
+
12
+ module Hanko
13
+ module Api
14
+ # Namespace module for Hanko Admin API resource classes.
15
+ module Admin
16
+ end
17
+
18
+ # Entry point for the Hanko Admin API, providing access to admin sub-resources.
19
+ class AdminNamespace
20
+ # Initialize the admin namespace.
21
+ #
22
+ # @param connection [Hanko::Connection] the HTTP connection to use
23
+ # @return [AdminNamespace] a new AdminNamespace instance
24
+ def initialize(connection)
25
+ @connection = connection
26
+ end
27
+
28
+ # Access the users resource, optionally scoped to a specific user.
29
+ #
30
+ # @param user_id [String, nil] optional user ID to scope to a single user context
31
+ # @return [Admin::Users, Admin::Users::UserContext] the users resource or a user-scoped context
32
+ def users(user_id = nil)
33
+ users_resource = Admin::Users.new(@connection)
34
+ user_id ? users_resource.call(user_id) : users_resource
35
+ end
36
+
37
+ # Access the webhooks resource.
38
+ #
39
+ # @return [Admin::Webhooks] the webhooks resource
40
+ def webhooks
41
+ Admin::Webhooks.new(@connection)
42
+ end
43
+
44
+ # Access the audit logs resource.
45
+ #
46
+ # @return [Admin::AuditLogs] the audit logs resource
47
+ def audit_logs
48
+ Admin::AuditLogs.new(@connection)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Hanko
6
+ module Api
7
+ # Base class for RESTful API resources providing standard CRUD operations.
8
+ # Subclasses inherit {#list}, {#get}, {#create}, {#update}, and {#delete}.
9
+ class BaseResource
10
+ # Initialize a new resource endpoint.
11
+ #
12
+ # @param connection [Hanko::Connection] the HTTP connection to use
13
+ # @param base_path [String] the base API path for this resource
14
+ # @return [BaseResource] a new BaseResource instance
15
+ def initialize(connection, base_path)
16
+ @connection = connection
17
+ @base_path = base_path
18
+ end
19
+
20
+ # List all resources, optionally filtered by query parameters.
21
+ #
22
+ # @param params [Hash] optional query parameters for filtering
23
+ # @return [Array<Resource>] an array of Resource objects
24
+ def list(params = {})
25
+ response = @connection.get(@base_path, params)
26
+ parse_array(response.body)
27
+ end
28
+
29
+ # Fetch a single resource by its ID.
30
+ #
31
+ # @param id [String] the unique identifier of the resource
32
+ # @return [Resource] the requested resource
33
+ def get(id)
34
+ response = @connection.get("#{@base_path}/#{id}")
35
+ parse_resource(response.body)
36
+ end
37
+
38
+ # Create a new resource with the given attributes.
39
+ #
40
+ # @param params [Hash] the attributes for the new resource
41
+ # @return [Resource] the newly created resource
42
+ def create(**params)
43
+ response = @connection.post(@base_path, params)
44
+ parse_resource(response.body)
45
+ end
46
+
47
+ # Update an existing resource by its ID.
48
+ #
49
+ # @param id [String] the unique identifier of the resource
50
+ # @param params [Hash] the attributes to update
51
+ # @return [Resource] the updated resource
52
+ def update(id, **params)
53
+ response = @connection.put("#{@base_path}/#{id}", params)
54
+ parse_resource(response.body)
55
+ end
56
+
57
+ # Delete a resource by its ID.
58
+ #
59
+ # @param id [String] the unique identifier of the resource
60
+ # @return [Boolean] true if deletion was successful
61
+ def delete(id)
62
+ @connection.delete("#{@base_path}/#{id}")
63
+ true
64
+ end
65
+
66
+ private
67
+
68
+ def parse_resource(body)
69
+ data = body.is_a?(String) ? JSON.parse(body) : body
70
+ Resource.new(data)
71
+ end
72
+
73
+ def parse_array(body)
74
+ data = body.is_a?(String) ? JSON.parse(body) : body
75
+ Resource.from_array(data)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Public
6
+ # Public resource for initiating authentication and profile flows.
7
+ class Flow
8
+ # Initialize the flow resource.
9
+ #
10
+ # @param connection [Hanko::Connection] the HTTP connection to use
11
+ # @return [Flow] a new Flow instance
12
+ def initialize(connection)
13
+ @connection = connection
14
+ end
15
+
16
+ # Initiate a login flow.
17
+ #
18
+ # @param params [Hash] optional parameters for the login flow
19
+ # @return [FlowResponse] the login flow response
20
+ def login(**params)
21
+ post_flow("/login", params)
22
+ end
23
+
24
+ # Initiate a registration flow.
25
+ #
26
+ # @param params [Hash] optional parameters for the registration flow
27
+ # @return [FlowResponse] the registration flow response
28
+ def registration(**params)
29
+ post_flow("/registration", params)
30
+ end
31
+
32
+ # Initiate a profile management flow.
33
+ #
34
+ # @param params [Hash] optional parameters for the profile flow
35
+ # @return [FlowResponse] the profile flow response
36
+ def profile(**params)
37
+ post_flow("/profile", params)
38
+ end
39
+
40
+ private
41
+
42
+ def post_flow(path, params)
43
+ body = params.empty? ? {} : params
44
+ response = @connection.post(path, body)
45
+ FlowResponse.new(JSON.parse(response.body))
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Public
6
+ # Public resource for validating Hanko sessions.
7
+ class Sessions
8
+ # Initialize the public sessions resource.
9
+ #
10
+ # @param connection [Hanko::Connection] the HTTP connection to use
11
+ # @return [Sessions] a new Sessions instance
12
+ def initialize(connection)
13
+ @connection = connection
14
+ end
15
+
16
+ # Validate the current session using cookies/headers from the connection.
17
+ #
18
+ # @return [Resource] the validated session resource
19
+ def validate
20
+ response = @connection.get("/sessions/validate")
21
+ Resource.new(JSON.parse(response.body))
22
+ end
23
+
24
+ # Validate a session by providing an explicit session token.
25
+ #
26
+ # @param session_token [String] the session token to validate
27
+ # @return [Resource] the validated session resource
28
+ def validate_token(session_token)
29
+ response = @connection.post("/sessions/validate", session_token: session_token)
30
+ Resource.new(JSON.parse(response.body))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ module Api
5
+ module Public
6
+ # Public resource for accessing .well-known discovery endpoints.
7
+ class WellKnown
8
+ # Initialize the well-known resource.
9
+ #
10
+ # @param connection [Hanko::Connection] the HTTP connection to use
11
+ # @return [WellKnown] a new WellKnown instance
12
+ def initialize(connection)
13
+ @connection = connection
14
+ end
15
+
16
+ # Fetch the JSON Web Key Set (JWKS) for token verification.
17
+ #
18
+ # @return [Resource] the JWKS resource
19
+ def jwks
20
+ response = @connection.get("/.well-known/jwks.json")
21
+ Resource.new(JSON.parse(response.body))
22
+ end
23
+
24
+ # Fetch the Hanko server configuration.
25
+ #
26
+ # @return [Resource] the configuration resource
27
+ def config
28
+ response = @connection.get("/.well-known/config")
29
+ Resource.new(JSON.parse(response.body))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "public/sessions"
4
+ require_relative "public/well_known"
5
+ require_relative "public/flow"
6
+
7
+ module Hanko
8
+ module Api
9
+ # Namespace module for Hanko Public API resource classes.
10
+ module Public
11
+ end
12
+
13
+ # Entry point for the Hanko Public API, providing access to public sub-resources.
14
+ class PublicNamespace
15
+ # Initialize the public namespace.
16
+ #
17
+ # @param connection [Hanko::Connection] the HTTP connection to use
18
+ # @return [PublicNamespace] a new PublicNamespace instance
19
+ def initialize(connection)
20
+ @connection = connection
21
+ end
22
+
23
+ # Access the sessions resource for session validation.
24
+ #
25
+ # @return [Public::Sessions] the sessions resource
26
+ def sessions
27
+ Public::Sessions.new(@connection)
28
+ end
29
+
30
+ # Access the .well-known resource for JWKS and configuration discovery.
31
+ #
32
+ # @return [Public::WellKnown] the well-known resource
33
+ def well_known
34
+ Public::WellKnown.new(@connection)
35
+ end
36
+
37
+ # Access the flow resource for login, registration, and profile flows.
38
+ #
39
+ # @return [Public::Flow] the flow resource
40
+ def flow
41
+ Public::Flow.new(@connection)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanko
4
+ # Main entry point for interacting with the Hanko API.
5
+ #
6
+ # A client merges any per-instance options with the global {Configuration},
7
+ # then exposes admin and public API namespaces.
8
+ #
9
+ # @example Create a client with inline options
10
+ # client = Hanko::Client.new(api_url: "https://example.hanko.io", api_key: "key")
11
+ # client.admin.users.list
12
+ #
13
+ # @example Create a client using global configuration
14
+ # Hanko.configure { |c| c.api_url = "https://example.hanko.io" }
15
+ # client = Hanko::Client.new
16
+ class Client
17
+ # @return [Configuration] the resolved configuration for this client
18
+ attr_reader :config
19
+
20
+ # Creates a new Hanko API client.
21
+ #
22
+ # Options override values from the global {Hanko.configuration}.
23
+ #
24
+ # @param options [Hash] configuration overrides
25
+ # @option options [String] :api_url the Hanko API base URL
26
+ # @option options [String] :api_key the API key for admin endpoints
27
+ # @option options [Integer] :timeout request timeout in seconds
28
+ # @option options [Integer] :open_timeout connection open timeout in seconds
29
+ # @option options [Integer] :retry_count number of retries on failure
30
+ # @option options [Array] :adapter Faraday adapter (for testing)
31
+ # @raise [ConfigurationError] if api_url is not set
32
+ def initialize(**options)
33
+ @adapter = options.delete(:adapter)
34
+ @config = build_config(options)
35
+ validate_config!
36
+ @connection = Connection.new(@config, adapter: @adapter)
37
+ end
38
+
39
+ # Returns the admin API namespace for managing users, emails, etc.
40
+ #
41
+ # @return [Api::AdminNamespace]
42
+ def admin
43
+ @admin ||= Api::AdminNamespace.new(@connection)
44
+ end
45
+
46
+ # Returns the public API namespace for flows, well-known endpoints, etc.
47
+ #
48
+ # @return [Api::PublicNamespace]
49
+ def public
50
+ @public ||= Api::PublicNamespace.new(@connection)
51
+ end
52
+
53
+ # Returns a human-readable representation with the API key redacted.
54
+ #
55
+ # @return [String]
56
+ def inspect
57
+ "#<#{self.class} api_url=#{config.api_url.inspect} api_key=[REDACTED]>"
58
+ end
59
+
60
+ private
61
+
62
+ def build_config(options)
63
+ base = Hanko.configuration
64
+ Configuration.new.tap do |c|
65
+ Configuration::ATTRIBUTES.each do |attr|
66
+ value = options.fetch(attr, base.send(attr))
67
+ c.send(:"#{attr}=", value)
68
+ end
69
+ end
70
+ end
71
+
72
+ def validate_config!
73
+ raise ConfigurationError, 'api_url is required' unless config.api_url
74
+ end
75
+ end
76
+ end