standard_id 0.2.4 → 0.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 144da6f9e7281b9b22e80c7ecdee847eb8d41f85571ab07846558f9ee565df83
4
- data.tar.gz: 5e3bdb2356d73520039fa35387a49beb55fe34501a5787510ff0359a4143470e
3
+ metadata.gz: 1943644d0423c990ca37c0c666c1bd23f3b968320b3e7ffd573a9c3ce7ee71e1
4
+ data.tar.gz: ddd8b3e73ec3f949e0b15b680891c0721aa7ef712c95d1fdacde275688ad5539
5
5
  SHA512:
6
- metadata.gz: 2b6daa2a3da9c30167cb2648c3adce23613913226c56a722106e5fc924631ee666c444273cfd5f1e603f16f6026d29183521704c947683c4cb011250c2af23e5
7
- data.tar.gz: a70e979d184c85620203291f1a67521342b2b7bb130814ecdb96f2eef384c233d5e285e557f59c6d6ac49a4512e71b7e112a1f13b73d3ce2e9b50876d6b501b2
6
+ metadata.gz: ee653052de174dc0c3fd6577a1edaaced24fdd530d883e08ded724e5a25a3657aa0e9ea3133d7609563ee2f6c34819278869b4476f97271be6c3e290160dacc3
7
+ data.tar.gz: 5c745b656babf628cf122f385f42dc7dbb33ad724e36637039462d457b28aa6edde5f77acd09a5f5e1bc0af27ec191da6ef86ef7137734f45798b45f0d0e9e87
@@ -44,8 +44,12 @@ StandardId.configure do |c|
44
44
  # email: ->(account:) { account.email },
45
45
  # display_name: ->(account:, client:) {
46
46
  # "#{account.name} for #{client.client_id}"
47
+ # },
48
+ # profile_id: ->(account:, audience:) {
49
+ # account.profiles.find_by(type: audience)&.id
47
50
  # }
48
51
  # }
52
+ # c.oauth.allowed_audiences = %w[web mobile admin] # Empty = no validation
49
53
 
50
54
  # Events
51
55
  # Enable or disable logging emitted via the internal event system
@@ -50,6 +50,7 @@ StandardConfig.schema.draw do
50
50
  field :client_secret, type: :string, default: nil
51
51
  field :scope_claims, type: :hash, default: -> { {} }
52
52
  field :claim_resolvers, type: :hash, default: -> { {} }
53
+ field :allowed_audiences, type: :array, default: -> { [] } # Empty = no validation, any audience allowed
53
54
  end
54
55
 
55
56
  scope :social do
@@ -5,7 +5,7 @@ module StandardId
5
5
  class JwtService
6
6
  ALGORITHM = "HS256"
7
7
  RESERVED_JWT_KEYS = %i[sub client_id scope grant_type exp iat aud iss nbf jti]
8
- BASE_SESSION_FIELDS = %i[account_id client_id scopes grant_type]
8
+ BASE_SESSION_FIELDS = %i[account_id client_id scopes grant_type aud]
9
9
 
10
10
  SESSION_CLASS = Concurrent::Delay.new do
11
11
  Struct.new(*(BASE_SESSION_FIELDS + claim_resolver_keys), keyword_init: true) do
@@ -49,6 +49,7 @@ module StandardId
49
49
  client_id: payload[:client_id],
50
50
  scopes: scopes,
51
51
  grant_type: payload[:grant_type],
52
+ aud: payload[:aud]
52
53
  )
53
54
  end
54
55
 
@@ -66,6 +66,10 @@ module StandardId
66
66
  def token_account
67
67
  @authorization_code&.account
68
68
  end
69
+
70
+ def audience
71
+ @authorization_code&.audience
72
+ end
69
73
  end
70
74
  end
71
75
  end
@@ -41,6 +41,11 @@ module StandardId
41
41
  true
42
42
  end
43
43
 
44
+ # Audience is bound to the refresh token - cannot be changed on refresh
45
+ def audience
46
+ @refresh_payload[:aud]
47
+ end
48
+
44
49
  def validate_scope_narrowing!
45
50
  return unless params[:scope].present?
46
51
 
@@ -35,6 +35,7 @@ module StandardId
35
35
  end
36
36
 
37
37
  def generate_token_response
38
+ validate_audience!
38
39
  emit_token_issuing
39
40
  expires_in = token_expiry
40
41
  payload = build_jwt_payload(expires_in)
@@ -77,8 +78,9 @@ module StandardId
77
78
  sub: subject_id,
78
79
  client_id: client_id,
79
80
  scope: token_scope,
81
+ aud: audience,
80
82
  grant_type: "refresh_token"
81
- }
83
+ }.compact
82
84
  StandardId::JwtService.encode(payload, expires_in: refresh_token_expiry)
83
85
  end
84
86
 
@@ -110,6 +112,20 @@ module StandardId
110
112
  params[:audience]
111
113
  end
112
114
 
115
+ def validate_audience!
116
+ allowed = StandardId.config.oauth.allowed_audiences
117
+ return if allowed.blank? # No restriction configured
118
+ return if audience.blank? # Audience not provided (optional)
119
+
120
+ # aud can be string or array per JWT spec
121
+ requested = Array(audience)
122
+ invalid = requested - allowed
123
+
124
+ if invalid.any?
125
+ raise StandardId::InvalidRequestError, "Invalid audience: #{invalid.join(', ')}"
126
+ end
127
+ end
128
+
113
129
  def claims_from_scope_mapping
114
130
  scope_claims = StandardId.config.oauth.scope_claims.with_indifferent_access
115
131
  resolvers = StandardId.config.oauth.claim_resolvers.with_indifferent_access
@@ -152,7 +168,8 @@ module StandardId
152
168
  @claim_resolvers_context ||= {
153
169
  client: token_client,
154
170
  account: token_account,
155
- request: request
171
+ request: request,
172
+ audience: audience
156
173
  }
157
174
  end
158
175
 
@@ -1,3 +1,3 @@
1
1
  module StandardId
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standard_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim