standard_id-apple 0.1.1 → 0.2.0

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: 63120ccfea7a05fb35a42c90548f441a7d719aa3d5a46e0bb9d72ec97e1e5129
4
- data.tar.gz: '0857aa7e1bbafae5621ce60aa2c3364b01931a836b8e0adc121b50bcfacf42af'
3
+ metadata.gz: 12a977e4ff2079df4c467f77c117bd3ea4564de05381b29514f7c1bbdec87380
4
+ data.tar.gz: c071fe2549d4dae82f12d98e435214a615e68fa892fd85ff2a0dda88290c1a9b
5
5
  SHA512:
6
- metadata.gz: da5566c05904516299901bc7cbafb42e97c59c6bfb516959c8a2e77b55afd34f976e07c503ac94781681b972349c82519f4053d97004c7dea6967738ded0fe4a
7
- data.tar.gz: 95da64b4f2c8deee61e18867133aa36d7ddea30985c276c266dcba0e8448712de8807c1040f224783621cb7319a998264c982ed0b96cb1e3b52a91447bfd1e0f
6
+ metadata.gz: c94b517719fa7da262ec4c189e4c3d791eef9e3e352afc4181844f0d353729bf167523932d9aab1c1eae88825001d9e87a7cf0c808b14182a6c081190ab956a3
7
+ data.tar.gz: b92eb9d4c48fefc7c59e1636f28e8a5483e13e58bdc83753716ca6e4956d334b8880e2a685a4288949b13c5048b433b788db0c874df9d2fd25809ae6b287e847
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.4.4
1
+ 4.0.1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
1
8
  ## [Unreleased]
2
9
 
10
+ ## [0.2.0] - 2026-04-21
11
+
12
+ ### Added
13
+
14
+ - Auto-register provider with StandardId via `Rails::Railtie` on `config.after_initialize`, so apps that bundle the gem no longer need an explicit initializer (#30)
15
+
16
+ ## [0.1.2] - 2026-01-13
17
+
18
+ ### Added
19
+
20
+ - Support nonce and passing custom parameters to Apple Sign In (#2)
21
+
22
+ ## [0.1.1] - 2025-12-24
23
+
24
+ ### Changed
25
+
26
+ - Standardized config access patterns
27
+
3
28
  ## [0.1.0] - 2025-12-20
4
29
 
5
- - Initial release
30
+ ### Added
31
+
32
+ - Initial release of Apple Sign In provider plugin for StandardId
data/CLAUDE.md ADDED
@@ -0,0 +1,26 @@
1
+ # CLAUDE.md
2
+
3
+ ## Worktree-Only Workflow (Enforced)
4
+
5
+ **All file modifications are blocked in the main checkout.** A PreToolUse hook (`enforce-worktree.sh`) rejects Edit, Write, and NotebookEdit operations targeting files outside a worktree. There are no opt-outs. Do not use Bash to write files in the main checkout either (e.g., `echo >`, `sed -i`, `tee`, `cp`) — the hook cannot intercept shell commands, so this rule is instruction-enforced.
6
+
7
+ Before writing any code, create a worktree:
8
+
9
+ ```bash
10
+ DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
11
+ DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
12
+ git fetch origin "$DEFAULT_BRANCH"
13
+ git worktree add .worktrees/<name> -b <branch-name> "origin/$DEFAULT_BRANCH"
14
+ ```
15
+
16
+ Then work inside `.worktrees/<name>/` for the rest of the session.
17
+
18
+ **Naming:** Use the Linear issue identifier if available (e.g., `.worktrees/<identifier>`), a task slug (e.g., `.worktrees/fix-auth-timeout`), or today's date (e.g., `.worktrees/2026-04-01`) as fallback.
19
+
20
+ **The hook allows modifications only when:**
21
+
22
+ 1. The file is inside a git worktree (detected via `git rev-parse --git-dir` returning a path under `.git/worktrees/`)
23
+ 2. Running in a CI/automated context where the checkout is already isolated
24
+ **Why this matters:** Working directly on the main checkout causes cross-contamination between sessions — uncommitted changes, wrong branches, and dirty state leak into unrelated work. Worktrees eliminate this entirely.
25
+
26
+ See the `/worktree` and `/start` skills for full conventions and flags.
@@ -12,40 +12,47 @@ module StandardId
12
12
  JWKS_URI = "#{ISSUER}/auth/keys".freeze
13
13
  DEFAULT_SCOPE = "name email".freeze
14
14
  DEFAULT_RESPONSE_MODE = "form_post".freeze
15
+ AUTHORIZATION_PARAM_DEFAULTS = {
16
+ scope: DEFAULT_SCOPE,
17
+ response_mode: DEFAULT_RESPONSE_MODE
18
+ }.freeze
15
19
 
16
20
  class << self
17
21
  def provider_name
18
22
  "apple"
19
23
  end
20
24
 
21
- def authorization_url(state:, redirect_uri:, **options)
22
- scope = options[:scope] || DEFAULT_SCOPE
23
- response_mode = options[:response_mode] || DEFAULT_RESPONSE_MODE
25
+ def supported_authorization_params
26
+ [:nonce, :scope, :response_mode]
27
+ end
24
28
 
29
+ def authorization_url(state:, redirect_uri:, **options)
25
30
  ensure_basic_credentials!
26
31
 
27
32
  query = {
28
33
  client_id: StandardId.config.apple_client_id,
29
- redirect_uri: redirect_uri,
34
+ redirect_uri:,
30
35
  response_type: "code",
31
- scope: scope,
32
- response_mode: response_mode,
33
- state: state
36
+ state:
34
37
  }
35
38
 
36
- "#{AUTH_ENDPOINT}?#{URI.encode_www_form(query)}"
39
+ supported_authorization_params.each do |param|
40
+ query[param] = options[param] || AUTHORIZATION_PARAM_DEFAULTS[param]
41
+ end
42
+
43
+ "#{AUTH_ENDPOINT}?#{URI.encode_www_form(query.compact)}"
37
44
  end
38
45
 
39
- def get_user_info(code: nil, id_token: nil, access_token: nil, redirect_uri: nil, **options)
46
+ def get_user_info(code: nil, id_token: nil, access_token: nil, redirect_uri: nil, nonce: nil, **options)
40
47
  client_id = options[:client_id] || StandardId.config.apple_client_id
41
48
 
42
49
  if id_token.present?
43
50
  build_response(
44
- verify_id_token(id_token: id_token, client_id: client_id),
51
+ verify_id_token(id_token: id_token, client_id: client_id, nonce: nonce),
45
52
  tokens: { id_token: id_token }
46
53
  )
47
54
  elsif code.present?
48
- exchange_code_for_user_info(code: code, redirect_uri: redirect_uri, client_id: client_id)
55
+ exchange_code_for_user_info(code: code, redirect_uri: redirect_uri, client_id: client_id, nonce: nonce)
49
56
  elsif access_token.present?
50
57
  raise StandardId::InvalidRequestError, "Access token login flow is not supported for Apple"
51
58
  else
@@ -82,7 +89,7 @@ module StandardId
82
89
  params.merge(client_id: client_id)
83
90
  end
84
91
 
85
- def exchange_code_for_user_info(code:, redirect_uri:, client_id: StandardId.config.apple_client_id)
92
+ def exchange_code_for_user_info(code:, redirect_uri:, client_id: StandardId.config.apple_client_id, nonce: nil)
86
93
  ensure_full_credentials!(client_id: client_id)
87
94
  raise StandardId::InvalidRequestError, "Missing authorization code" if code.blank?
88
95
 
@@ -108,7 +115,7 @@ module StandardId
108
115
  raise StandardId::InvalidRequestError, "Apple response missing id_token" if id_token.blank?
109
116
 
110
117
  tokens = extract_token_payload(parsed_token)
111
- user_info = verify_id_token(id_token: id_token, client_id: client_id)
118
+ user_info = verify_id_token(id_token: id_token, client_id: client_id, nonce: nonce)
112
119
 
113
120
  build_response(user_info, tokens: tokens)
114
121
  rescue StandardError => e
@@ -117,7 +124,7 @@ module StandardId
117
124
  raise StandardId::OAuthError, e.message, cause: e
118
125
  end
119
126
 
120
- def verify_id_token(id_token:, client_id: StandardId.config.apple_client_id)
127
+ def verify_id_token(id_token:, client_id: StandardId.config.apple_client_id, nonce: nil)
121
128
  raise StandardId::InvalidRequestError, "Missing id_token" if id_token.blank?
122
129
  raise StandardId::InvalidRequestError, "Apple client_id is not configured" if client_id.blank?
123
130
 
@@ -137,6 +144,15 @@ module StandardId
137
144
  verify_aud: true
138
145
  )
139
146
 
147
+ # Validate nonce if provided (web flow with server-generated nonce)
148
+ if nonce.present?
149
+ token_nonce = verified_payload["nonce"]
150
+ if token_nonce != nonce
151
+ raise StandardId::InvalidRequestError,
152
+ "ID token nonce mismatch. Expected: #{nonce}, got: #{token_nonce}"
153
+ end
154
+ end
155
+
140
156
  {
141
157
  "sub" => verified_payload["sub"],
142
158
  "email" => verified_payload["email"],
@@ -224,5 +240,3 @@ module StandardId
224
240
  end
225
241
  end
226
242
  end
227
-
228
- StandardId::ProviderRegistry.register(:apple, StandardId::Providers::Apple)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StandardId
4
+ module Apple
5
+ class Railtie < ::Rails::Railtie
6
+ config.after_initialize do
7
+ StandardId::ProviderRegistry.register(:apple, StandardId::Providers::Apple)
8
+
9
+ Rails.logger.debug("[StandardId::Apple] registered provider") if Rails.logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StandardId
4
4
  module Apple
5
- VERSION = "0.1.1"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
@@ -2,3 +2,4 @@ require "active_support/core_ext/numeric/time"
2
2
  require "active_support/core_ext/hash/indifferent_access"
3
3
  require "standard_id"
4
4
  require "standard_id/apple/providers/apple"
5
+ require "standard_id/apple/railtie" if defined?(Rails)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standard_id-apple
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim
@@ -69,12 +69,14 @@ files:
69
69
  - ".rubocop.yml"
70
70
  - ".ruby-version"
71
71
  - CHANGELOG.md
72
+ - CLAUDE.md
72
73
  - CODE_OF_CONDUCT.md
73
74
  - LICENSE.txt
74
75
  - README.md
75
76
  - Rakefile
76
77
  - lib/standard_id/apple.rb
77
78
  - lib/standard_id/apple/providers/apple.rb
79
+ - lib/standard_id/apple/railtie.rb
78
80
  - lib/standard_id/apple/version.rb
79
81
  homepage: https://github.com/rarebit-one/standard_id_apple
80
82
  licenses:
@@ -83,6 +85,7 @@ metadata:
83
85
  homepage_uri: https://github.com/rarebit-one/standard_id_apple
84
86
  source_code_uri: https://github.com/rarebit-one/standard_id_apple
85
87
  changelog_uri: https://github.com/rarebit-one/standard_id_apple/blob/main/CHANGELOG.md
88
+ bug_tracker_uri: https://github.com/rarebit-one/standard_id_apple/issues
86
89
  rdoc_options: []
87
90
  require_paths:
88
91
  - lib
@@ -97,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
100
  - !ruby/object:Gem::Version
98
101
  version: '0'
99
102
  requirements: []
100
- rubygems_version: 3.6.7
103
+ rubygems_version: 4.0.3
101
104
  specification_version: 4
102
105
  summary: Apple Sign In provider plugin for the StandardId engine.
103
106
  test_files: []