aha_builder_core 1.0.0 → 1.0.3
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 +4 -4
- data/README.md +14 -26
- data/lib/aha/auth/client.rb +15 -18
- data/lib/aha/auth/configuration.rb +1 -1
- data/lib/aha/auth/sessions_resource.rb +2 -0
- data/lib/aha/auth/user.rb +2 -0
- data/lib/aha/auth/version.rb +1 -1
- data/lib/aha/auth.rb +2 -4
- metadata +17 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3bfa1fb612c68e9997d4058381ef9c4b6b8d7eb61ddcbb52800fac41ace7fcd0
|
|
4
|
+
data.tar.gz: e673fd8edc82b0ae0f1a7c32ecf82bdd6c8368ebe2b8b626dc4e5d1cf6d6b696
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2b43eeff2fbea68a9b7b908097ca88bf858504035671808c8dac2716b0621d37219c06f92aaed8d9be7eb6571da665a1f8fed95f52cf02f3d02ba4151c29898
|
|
7
|
+
data.tar.gz: 927e0f48d3a1d2e4cb492ccefa7cb3bc377468ac7c57b3896abcaaa449a3b85a42cad99392927f0733127b28a7fe612d0f365c55060993b3c545c8c193048606
|
data/README.md
CHANGED
|
@@ -12,20 +12,7 @@ gem "aha_builder_core", path: "engines/builder_core/client"
|
|
|
12
12
|
|
|
13
13
|
## Configuration
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```ruby
|
|
18
|
-
require "aha_builder_core"
|
|
19
|
-
|
|
20
|
-
Aha::Auth.configure do |config|
|
|
21
|
-
config.server_url = "https://secure.aha.io" # Auth server URL
|
|
22
|
-
config.client_id = "your-client-id" # ID of the builder application
|
|
23
|
-
config.api_key = "your-api-key" # For server-to-server auth
|
|
24
|
-
config.jwks_cache_ttl = 3600 # JWKS cache duration (default: 1 hour)
|
|
25
|
-
config.refresh_threshold = 120 # Seconds before expiry to refresh (default: 2 min)
|
|
26
|
-
config.timeout = 30 # HTTP timeout in seconds
|
|
27
|
-
end
|
|
28
|
-
```
|
|
15
|
+
No configuration is necessary and no environment variables are necessary.
|
|
29
16
|
|
|
30
17
|
## Authentication Flow
|
|
31
18
|
|
|
@@ -38,11 +25,12 @@ Redirect users to the authentication and signup UI:
|
|
|
38
25
|
```ruby
|
|
39
26
|
url = Aha::Auth.login_url(
|
|
40
27
|
state: { return_to: "/" }.to_json,
|
|
41
|
-
redirect_uri: "#{ENV['APPLICATION_URL']}/callback"
|
|
42
28
|
)
|
|
43
29
|
redirect_to url
|
|
44
30
|
```
|
|
45
31
|
|
|
32
|
+
Redirecting to the login_url must be done with a full page load. It will not work using XHR.
|
|
33
|
+
|
|
46
34
|
### Exchange Authorization Code
|
|
47
35
|
|
|
48
36
|
In the `/callback` action callback, you must exchange the code for a session token and refresh token:
|
|
@@ -54,11 +42,11 @@ result = Aha::Auth.authenticate_with_code(code: params[:code])
|
|
|
54
42
|
# refresh_token: "...",
|
|
55
43
|
# expires_at: Time,
|
|
56
44
|
# user: {
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
45
|
+
# id: "user-uuid",
|
|
46
|
+
# first_name: "Jane",
|
|
47
|
+
# last_name: "Doe",
|
|
48
|
+
# email: "jane.doe@example.com",
|
|
49
|
+
# email_verified: true
|
|
62
50
|
# }
|
|
63
51
|
# }
|
|
64
52
|
```
|
|
@@ -68,8 +56,8 @@ result = Aha::Auth.authenticate_with_code(code: params[:code])
|
|
|
68
56
|
The `user` object returned contains the authenticated user's profile information from the Builder Core system:
|
|
69
57
|
|
|
70
58
|
- `id`: The unique identifier for the user in Builder Core
|
|
71
|
-
- `first_name`: User's first name
|
|
72
|
-
- `last_name`: User's last name
|
|
59
|
+
- `first_name`: User's first name. first_name is optional and may not be present.
|
|
60
|
+
- `last_name`: User's last name. last_name is optional and may not be present.
|
|
73
61
|
- `email`: User's email address
|
|
74
62
|
- `email_verified`: Boolean indicating if the email has been verified
|
|
75
63
|
|
|
@@ -86,10 +74,10 @@ local_user = User.find_or_initialize_by(auth_identifier: result[:user]["id"])
|
|
|
86
74
|
|
|
87
75
|
# Update local user attributes
|
|
88
76
|
local_user.update!(
|
|
89
|
-
email: result[:user][
|
|
90
|
-
first_name: result[:user][
|
|
91
|
-
last_name: result[:user][
|
|
92
|
-
email_verified: result[:user][
|
|
77
|
+
email: result[:user][:email],
|
|
78
|
+
first_name: result[:user][:first_name],
|
|
79
|
+
last_name: result[:user][:last_name],
|
|
80
|
+
email_verified: result[:user][:email_verified]
|
|
93
81
|
)
|
|
94
82
|
|
|
95
83
|
# Store tokens in session or database
|
data/lib/aha/auth/client.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
|
4
|
+
|
|
3
5
|
module Aha
|
|
4
6
|
module Auth
|
|
5
7
|
# HTTP client for communicating with the BuilderCore auth server
|
|
@@ -47,14 +49,16 @@ module Aha
|
|
|
47
49
|
# @param refresh_token [String, nil] Optional refresh token for automatic refresh
|
|
48
50
|
# @return [Session] Session validation result
|
|
49
51
|
def validate_session(session_token, refresh_token: nil)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
begin
|
|
53
|
+
claims = decode_and_verify_token(session_token)
|
|
54
|
+
return Session.from_claims(claims) if claims
|
|
55
|
+
rescue ExpiredTokenError
|
|
56
|
+
# Token has expired, attempt refresh
|
|
57
|
+
end
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
exp = claims["exp"]
|
|
55
|
-
if exp && refresh_token && should_refresh?(exp)
|
|
59
|
+
if refresh_token
|
|
56
60
|
begin
|
|
57
|
-
tokens =
|
|
61
|
+
tokens = authenticate_with_refresh_token(refresh_token: refresh_token)
|
|
58
62
|
new_claims = decode_and_verify_token(tokens[:session_token])
|
|
59
63
|
|
|
60
64
|
return Session.from_claims(
|
|
@@ -64,13 +68,11 @@ module Aha
|
|
|
64
68
|
new_refresh_token: tokens[:refresh_token]
|
|
65
69
|
)
|
|
66
70
|
rescue Error
|
|
67
|
-
|
|
68
|
-
# Refresh failed, return session with original token if still valid
|
|
69
|
-
return Session.invalid if Time.at(exp).utc < Time.now.utc
|
|
71
|
+
return Session.invalid
|
|
70
72
|
end
|
|
71
73
|
end
|
|
72
74
|
|
|
73
|
-
Session.
|
|
75
|
+
Session.invalid
|
|
74
76
|
rescue InvalidTokenError, ExpiredTokenError
|
|
75
77
|
Session.invalid
|
|
76
78
|
end
|
|
@@ -80,7 +82,7 @@ module Aha
|
|
|
80
82
|
# @param session_token [String] The session token to revoke
|
|
81
83
|
# @return [Boolean] true if successful
|
|
82
84
|
def logout(session_token:)
|
|
83
|
-
get("/api/core/
|
|
85
|
+
get("/api/core/auth_ui/logout", headers: { "Authorization" => "Bearer #{session_token}" })
|
|
84
86
|
true
|
|
85
87
|
rescue ApiError
|
|
86
88
|
false
|
|
@@ -90,8 +92,7 @@ module Aha
|
|
|
90
92
|
#
|
|
91
93
|
# @return [Hash] The JWKS response
|
|
92
94
|
def fetch_jwks
|
|
93
|
-
|
|
94
|
-
handle_response(response)
|
|
95
|
+
get("/api/core/auth/jwks/#{@configuration.client_id}")
|
|
95
96
|
end
|
|
96
97
|
|
|
97
98
|
private
|
|
@@ -125,17 +126,13 @@ module Aha
|
|
|
125
126
|
raise InvalidTokenError, "Invalid token: #{e.message}"
|
|
126
127
|
end
|
|
127
128
|
|
|
128
|
-
def should_refresh?(exp)
|
|
129
|
-
Time.at(exp).utc - Time.now.utc <= @configuration.refresh_threshold
|
|
130
|
-
end
|
|
131
|
-
|
|
132
129
|
def parse_token_response(response)
|
|
133
130
|
{
|
|
134
131
|
session_token: response["session_token"],
|
|
135
132
|
refresh_token: response["refresh_token"],
|
|
136
133
|
expires_at: response["expires_at"] ? Time.iso8601(response["expires_at"]) : nil,
|
|
137
134
|
user: response["user"]
|
|
138
|
-
}
|
|
135
|
+
}.with_indifferent_access
|
|
139
136
|
end
|
|
140
137
|
|
|
141
138
|
def get(path, headers: {})
|
|
@@ -22,7 +22,7 @@ module Aha
|
|
|
22
22
|
attr_accessor :timeout
|
|
23
23
|
|
|
24
24
|
def initialize
|
|
25
|
-
@server_url = ENV.fetch("AHA_CORE_SERVER_URL",
|
|
25
|
+
@server_url = ENV.fetch("AHA_CORE_SERVER_URL", "https://secure.aha.io/api/core")
|
|
26
26
|
@api_key = ENV.fetch("AHA_CORE_API_KEY", nil)
|
|
27
27
|
@client_id = ENV.fetch("APPLICATION_ID", nil)
|
|
28
28
|
@jwks_cache_ttl = 3600 # 1 hour
|
data/lib/aha/auth/user.rb
CHANGED
data/lib/aha/auth/version.rb
CHANGED
data/lib/aha/auth.rb
CHANGED
|
@@ -41,15 +41,13 @@ module Aha
|
|
|
41
41
|
# Generate login URL for redirecting users to the auth server
|
|
42
42
|
#
|
|
43
43
|
# @param state [String] Optional state parameter to pass through the auth flow
|
|
44
|
-
# @param redirect_uri [String] Optional redirect URI after authentication
|
|
45
44
|
# @return [String] The login URL
|
|
46
|
-
def login_url(state: nil
|
|
45
|
+
def login_url(state: nil)
|
|
47
46
|
params = { client_id: configuration.client_id }
|
|
48
47
|
params[:state] = state if state
|
|
49
|
-
params[:redirect_uri] = redirect_uri if redirect_uri
|
|
50
48
|
|
|
51
49
|
query = URI.encode_www_form(params)
|
|
52
|
-
"#{configuration.server_url}/
|
|
50
|
+
"#{configuration.server_url}/auth_ui/start?#{query}"
|
|
53
51
|
end
|
|
54
52
|
|
|
55
53
|
# Exchange an authorization code for tokens
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aha_builder_core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aha! Labs Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: concurrent-ruby
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -124,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
124
138
|
requirements:
|
|
125
139
|
- - ">="
|
|
126
140
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: 3.
|
|
141
|
+
version: 3.2.0
|
|
128
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
143
|
requirements:
|
|
130
144
|
- - ">="
|