omniauth-yahoojp 0.2.0 → 1.0.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 +5 -5
- data/.github/workflows/claude-code-review.yml +78 -0
- data/.github/workflows/claude.yml +64 -0
- data/CLAUDE.md +49 -0
- data/Gemfile +1 -1
- data/README.md +69 -5
- data/lib/omniauth/strategies/yahoojp.rb +34 -8
- data/lib/omniauth-yahoojp/version.rb +1 -1
- data/omniauth-yahoojp.gemspec +7 -6
- data/spec/omniauth/strategies/yahoojp_spec.rb +276 -10
- data/spec/spec_helper.rb +0 -2
- metadata +42 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 16ae4d397a52eca91f5a45f36770e3ec1162bda6f607a1c2bbd5142ee9799b9c
|
|
4
|
+
data.tar.gz: 7989bc85f42e4ae4e6b2420e5d3a6c94355a87db5ba0997b1a1a8a62249ae088
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6f857f7d5604801d3aff235992b49d925a889e6ca6458400ceb746abe617594a8fa5ab229312f332f34df6fae83d3af508b33f39fd5d3c93bf4a611884395d9
|
|
7
|
+
data.tar.gz: 8c2a1ca936c8c89adbd4655d01021e14a7e669965be3015fd028df1bcb0c82164a66b90f116056c9d21963f6d5b22ae0ca3329ea9e13001336149f921f344be0
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Claude Code Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize]
|
|
6
|
+
# Optional: Only run on specific file changes
|
|
7
|
+
# paths:
|
|
8
|
+
# - "src/**/*.ts"
|
|
9
|
+
# - "src/**/*.tsx"
|
|
10
|
+
# - "src/**/*.js"
|
|
11
|
+
# - "src/**/*.jsx"
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude-review:
|
|
15
|
+
# Optional: Filter by PR author
|
|
16
|
+
# if: |
|
|
17
|
+
# github.event.pull_request.user.login == 'external-contributor' ||
|
|
18
|
+
# github.event.pull_request.user.login == 'new-developer' ||
|
|
19
|
+
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
|
20
|
+
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
pull-requests: read
|
|
25
|
+
issues: read
|
|
26
|
+
id-token: write
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout repository
|
|
30
|
+
uses: actions/checkout@v4
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 1
|
|
33
|
+
|
|
34
|
+
- name: Run Claude Code Review
|
|
35
|
+
id: claude-review
|
|
36
|
+
uses: anthropics/claude-code-action@beta
|
|
37
|
+
with:
|
|
38
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
|
+
|
|
40
|
+
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
|
|
41
|
+
# model: "claude-opus-4-20250514"
|
|
42
|
+
|
|
43
|
+
# Direct prompt for automated review (no @claude mention needed)
|
|
44
|
+
direct_prompt: |
|
|
45
|
+
Please review this pull request and provide feedback on:
|
|
46
|
+
- Code quality and best practices
|
|
47
|
+
- Potential bugs or issues
|
|
48
|
+
- Performance considerations
|
|
49
|
+
- Security concerns
|
|
50
|
+
- Test coverage
|
|
51
|
+
|
|
52
|
+
Be constructive and helpful in your feedback.
|
|
53
|
+
|
|
54
|
+
# Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
|
|
55
|
+
# use_sticky_comment: true
|
|
56
|
+
|
|
57
|
+
# Optional: Customize review based on file types
|
|
58
|
+
# direct_prompt: |
|
|
59
|
+
# Review this PR focusing on:
|
|
60
|
+
# - For TypeScript files: Type safety and proper interface usage
|
|
61
|
+
# - For API endpoints: Security, input validation, and error handling
|
|
62
|
+
# - For React components: Performance, accessibility, and best practices
|
|
63
|
+
# - For tests: Coverage, edge cases, and test quality
|
|
64
|
+
|
|
65
|
+
# Optional: Different prompts for different authors
|
|
66
|
+
# direct_prompt: |
|
|
67
|
+
# ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' &&
|
|
68
|
+
# 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
|
|
69
|
+
# 'Please provide a thorough code review focusing on our coding standards and best practices.' }}
|
|
70
|
+
|
|
71
|
+
# Optional: Add specific tools for running tests or linting
|
|
72
|
+
# allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
|
|
73
|
+
|
|
74
|
+
# Optional: Skip review for certain conditions
|
|
75
|
+
# if: |
|
|
76
|
+
# !contains(github.event.pull_request.title, '[skip-review]') &&
|
|
77
|
+
# !contains(github.event.pull_request.title, '[WIP]')
|
|
78
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pull-requests: read
|
|
24
|
+
issues: read
|
|
25
|
+
id-token: write
|
|
26
|
+
actions: read # Required for Claude to read CI results on PRs
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 1
|
|
32
|
+
|
|
33
|
+
- name: Run Claude Code
|
|
34
|
+
id: claude
|
|
35
|
+
uses: anthropics/claude-code-action@beta
|
|
36
|
+
with:
|
|
37
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
|
+
|
|
39
|
+
# This is an optional setting that allows Claude to read CI results on PRs
|
|
40
|
+
additional_permissions: |
|
|
41
|
+
actions: read
|
|
42
|
+
|
|
43
|
+
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
|
|
44
|
+
# model: "claude-opus-4-20250514"
|
|
45
|
+
|
|
46
|
+
# Optional: Customize the trigger phrase (default: @claude)
|
|
47
|
+
# trigger_phrase: "/claude"
|
|
48
|
+
|
|
49
|
+
# Optional: Trigger when specific user is assigned to an issue
|
|
50
|
+
# assignee_trigger: "claude-bot"
|
|
51
|
+
|
|
52
|
+
# Optional: Allow Claude to run specific commands
|
|
53
|
+
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
|
|
54
|
+
|
|
55
|
+
# Optional: Add custom instructions for Claude to customize its behavior for your project
|
|
56
|
+
# custom_instructions: |
|
|
57
|
+
# Follow our coding standards
|
|
58
|
+
# Ensure all new code has tests
|
|
59
|
+
# Use TypeScript for new files
|
|
60
|
+
|
|
61
|
+
# Optional: Custom environment variables for Claude
|
|
62
|
+
# claude_env: |
|
|
63
|
+
# NODE_ENV: test
|
|
64
|
+
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Development Commands
|
|
6
|
+
|
|
7
|
+
### Testing
|
|
8
|
+
- `rake spec` or `rspec` - Run all tests
|
|
9
|
+
- `rspec spec/omniauth/strategies/yahoojp_spec.rb` - Run specific test file
|
|
10
|
+
- `rake` - Default task runs specs
|
|
11
|
+
|
|
12
|
+
### Development Tools
|
|
13
|
+
- `guard` - File watcher for automatic test running (configured via Guardfile)
|
|
14
|
+
- `bundle install` - Install gem dependencies
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
This is a Ruby gem that implements an OmniAuth strategy for Yahoo! JAPAN's YConnect OAuth 2.0 service.
|
|
19
|
+
|
|
20
|
+
### Core Components
|
|
21
|
+
|
|
22
|
+
**Main Strategy**: `lib/omniauth/strategies/yahoojp.rb`
|
|
23
|
+
- Inherits from `OmniAuth::Strategies::OAuth2`
|
|
24
|
+
- Implements Yahoo! JAPAN YConnect v2 API endpoints
|
|
25
|
+
- Handles OAuth 2.0 authorization code flow with basic auth for token exchange
|
|
26
|
+
- Supports YConnect-specific parameters: display, prompt, scope, bail
|
|
27
|
+
|
|
28
|
+
**Key Implementation Details**:
|
|
29
|
+
- Uses `https://auth.login.yahoo.co.jp` as OAuth provider
|
|
30
|
+
- YConnect v2 endpoints: `/yconnect/v2/authorization` and `/yconnect/v2/token`
|
|
31
|
+
- User info endpoint: `https://userinfo.yahooapis.jp/yconnect/v2/attribute`
|
|
32
|
+
- Custom `build_access_token` method for Yahoo-specific auth headers
|
|
33
|
+
- Supports Japanese locale-specific fields (kana, kanji names)
|
|
34
|
+
|
|
35
|
+
### File Structure
|
|
36
|
+
- `lib/omniauth-yahoojp.rb` - Main entry point, requires the strategy
|
|
37
|
+
- `lib/omniauth-yahoojp/version.rb` - Gem version
|
|
38
|
+
- `lib/omniauth/strategies/yahoojp.rb` - Strategy implementation
|
|
39
|
+
- `spec/` - RSpec tests
|
|
40
|
+
|
|
41
|
+
### Dependencies
|
|
42
|
+
- `omniauth` and `omniauth-oauth2` for OAuth framework
|
|
43
|
+
- `httpauth` for HTTP basic authentication headers
|
|
44
|
+
|
|
45
|
+
## Downstream Test Project
|
|
46
|
+
|
|
47
|
+
- [`omniauth-yahoojp-tester-rails5`](https://github.com/mikanmarusan/omniauth-yahoojp-tester-rails5) is a Rails 5 app that consumes this gem for integration testing.
|
|
48
|
+
- Its CLAUDE.md documents the exact API surface used and cross-project update rules.
|
|
49
|
+
- Use `/add-dir ../omniauth-yahoojp-tester-rails5` to add it for cross-project awareness when making API changes.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**These notes are based on master, please see tags for README pertaining to specific releases.**
|
|
4
4
|
|
|
5
|
-
This is the
|
|
5
|
+
This is the OmniAuth strategy for authenticating to Yahoo! JAPAN( [YConnect](http://developer.yahoo.co.jp/yconnect/v2/) ).
|
|
6
6
|
To use it, you'll need to sign up for a YConnect Client ID and Secret
|
|
7
7
|
on the [Yahoo! JAPAN Developer Network](https://e.developer.yahoo.co.jp/dashboard/).
|
|
8
8
|
|
|
@@ -22,13 +22,14 @@ Then `bundle install`.
|
|
|
22
22
|
|
|
23
23
|
`OmniAuth::Strategies::YahooJp` is simply a Rack middleware. Read the OmniAuth docs for detailed instructions: https://github.com/intridea/omniauth.
|
|
24
24
|
|
|
25
|
-
YConnect API v2 lets you set scopes to provide granular access to different types of data:
|
|
25
|
+
YConnect API v2 lets you set scopes to provide granular access to different types of data:
|
|
26
26
|
|
|
27
27
|
```ruby
|
|
28
28
|
Rails.application.config.middleware.use OmniAuth::Builder do
|
|
29
|
-
provider :yahoojp, ENV['YAHOOJP_KEY'], ENV['YAHOOJP_SECRET'],
|
|
29
|
+
provider :yahoojp, ENV['YAHOOJP_KEY'], ENV['YAHOOJP_SECRET'],
|
|
30
30
|
{
|
|
31
|
-
scope: "openid profile email address"
|
|
31
|
+
scope: "openid profile email address",
|
|
32
|
+
userinfo_access: true # default: true
|
|
32
33
|
}
|
|
33
34
|
end
|
|
34
35
|
```
|
|
@@ -50,6 +51,24 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
|
|
50
51
|
end
|
|
51
52
|
```
|
|
52
53
|
|
|
54
|
+
### `userinfo_access` Option
|
|
55
|
+
|
|
56
|
+
Controls how user profile information is retrieved.
|
|
57
|
+
|
|
58
|
+
- `userinfo_access: true` (default) — Calls the UserInfo API (`https://userinfo.yahooapis.jp/yconnect/v2/attribute`) to retrieve full profile information including name variants (kana, kanji), gender, locale, birthdate, nickname, picture, email, and address.
|
|
59
|
+
- `userinfo_access: false` — Skips the UserInfo API call and extracts profile information from the `id_token` claims instead. This is useful when your application does not have access to the UserInfo API.
|
|
60
|
+
|
|
61
|
+
> **Note:** The fields available in `id_token` claims may differ from those returned by the UserInfo API. The `id_token` typically contains a subset of profile fields depending on the requested scopes. Yahoo! JAPAN has made the UserInfo API access-restricted, so some applications may need to rely on `id_token` claims.
|
|
62
|
+
|
|
63
|
+
### ID Token
|
|
64
|
+
|
|
65
|
+
When the `openid` scope is requested, the strategy automatically captures the `id_token` returned by Yahoo! JAPAN's token endpoint.
|
|
66
|
+
|
|
67
|
+
- `credentials.id_token` — The raw JWT string as returned from the token endpoint.
|
|
68
|
+
- `extra.id_token_claims` — The decoded claims hash from the `id_token`.
|
|
69
|
+
|
|
70
|
+
The `id_token` signature verification is skipped because the token is received directly from Yahoo! JAPAN's token endpoint over TLS in the Authorization Code Flow, which guarantees its authenticity.
|
|
71
|
+
|
|
53
72
|
### API Version
|
|
54
73
|
|
|
55
74
|
OmniAuth YahooJp uses versioned API endpoints by default (current v2). You can configure a different version via `client_options` hash passed to `provider`, specifically you should change the version in the `site` and `authorize_url` parameters. For example, to change to v1:
|
|
@@ -60,7 +79,6 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
|
|
60
79
|
{
|
|
61
80
|
scope: "openid profile email address",
|
|
62
81
|
client_options: {
|
|
63
|
-
site: 'https://auth.login.yahoo.co.jp',
|
|
64
82
|
authorize_url: '/yconnect/v1/authorization',
|
|
65
83
|
token_url: '/yconnect/v1/token'
|
|
66
84
|
}
|
|
@@ -68,6 +86,52 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
|
|
68
86
|
end
|
|
69
87
|
```
|
|
70
88
|
|
|
89
|
+
## Auth Hash
|
|
90
|
+
|
|
91
|
+
Here is an example of the auth hash available in `request.env['omniauth.auth']`:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
{
|
|
95
|
+
provider: "yahoojp",
|
|
96
|
+
uid: "abcdefg",
|
|
97
|
+
info: {
|
|
98
|
+
sub: "abcdefg",
|
|
99
|
+
name: "山田 太郎",
|
|
100
|
+
given_name: "太郎",
|
|
101
|
+
given_name_ja_kana_jp: "タロウ",
|
|
102
|
+
given_name_ja_hani_jp: "太郎",
|
|
103
|
+
family_name: "山田",
|
|
104
|
+
family_name_ja_kana_jp: "ヤマダ",
|
|
105
|
+
family_name_ja_hani_jp: "山田",
|
|
106
|
+
gender: "male",
|
|
107
|
+
locale: "ja-JP",
|
|
108
|
+
email: "example@yahoo.co.jp",
|
|
109
|
+
email_verified: true
|
|
110
|
+
},
|
|
111
|
+
credentials: {
|
|
112
|
+
token: "ACCESS_TOKEN",
|
|
113
|
+
refresh_token: "REFRESH_TOKEN",
|
|
114
|
+
expires_at: 1496120719,
|
|
115
|
+
expires: true,
|
|
116
|
+
id_token: "eyJhbGciOiJSUzI1NiIs..."
|
|
117
|
+
},
|
|
118
|
+
extra: {
|
|
119
|
+
raw_info: { ... }, # Full response from UserInfo API (or id_token claims)
|
|
120
|
+
id_token: "eyJhbGciOiJSUzI1NiIs...", # Raw JWT string
|
|
121
|
+
id_token_claims: { # Decoded id_token claims
|
|
122
|
+
iss: "https://auth.login.yahoo.co.jp/yconnect/v2",
|
|
123
|
+
sub: "abcdefg",
|
|
124
|
+
aud: ["YOUR_CLIENT_ID"],
|
|
125
|
+
exp: 1496120719,
|
|
126
|
+
iat: 1496117119,
|
|
127
|
+
nonce: "..."
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> **Note:** Available fields in `info` and `extra.raw_info` depend on the requested scopes and the `userinfo_access` setting.
|
|
134
|
+
|
|
71
135
|
## License
|
|
72
136
|
|
|
73
137
|
Copyright (c) 2013 by mikanmarusan
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'omniauth-oauth2'
|
|
2
2
|
require 'httpauth'
|
|
3
|
+
require 'json/jwt'
|
|
3
4
|
|
|
4
5
|
module OmniAuth
|
|
5
6
|
module Strategies
|
|
@@ -14,10 +15,7 @@ module OmniAuth
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
option :authorize_options, [:display, :prompt, :scope, :bail]
|
|
17
|
-
|
|
18
|
-
def request_phase
|
|
19
|
-
super
|
|
20
|
-
end
|
|
18
|
+
option :userinfo_access, true
|
|
21
19
|
|
|
22
20
|
uid { raw_info['sub'] }
|
|
23
21
|
|
|
@@ -39,19 +37,47 @@ module OmniAuth
|
|
|
39
37
|
:picture => raw_info['picture'],
|
|
40
38
|
:email => raw_info['email'],
|
|
41
39
|
:email_verified => raw_info['email_verified'],
|
|
42
|
-
:address => raw_info['address'],
|
|
40
|
+
:address => raw_info['address'],
|
|
43
41
|
})
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
extra do
|
|
47
45
|
hash = {}
|
|
48
46
|
hash[:raw_info] = raw_info unless skip_info?
|
|
47
|
+
hash[:id_token] = id_token if id_token
|
|
48
|
+
hash[:id_token_claims] = id_token_claims if id_token
|
|
49
49
|
prune! hash
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
credentials do
|
|
53
|
+
hash = {'token' => access_token.token}
|
|
54
|
+
hash['refresh_token'] = access_token.refresh_token if access_token.refresh_token
|
|
55
|
+
hash['expires_at'] = access_token.expires_at if access_token.expires?
|
|
56
|
+
hash['expires'] = access_token.expires?
|
|
57
|
+
hash['id_token'] = id_token if id_token
|
|
58
|
+
hash
|
|
59
|
+
end
|
|
60
|
+
|
|
52
61
|
def raw_info
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
@raw_info ||= if options.userinfo_access
|
|
63
|
+
access_token.options[:mode] = :header
|
|
64
|
+
access_token.get('https://userinfo.yahooapis.jp/yconnect/v2/attribute').parsed
|
|
65
|
+
elsif id_token
|
|
66
|
+
id_token_claims
|
|
67
|
+
else
|
|
68
|
+
{}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def id_token
|
|
73
|
+
@id_token ||= access_token&.params&.dig('id_token').presence
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def id_token_claims
|
|
77
|
+
return nil unless id_token
|
|
78
|
+
# Signature verification is skipped because the id_token was received
|
|
79
|
+
# directly from Yahoo's token endpoint over TLS (Authorization Code Flow).
|
|
80
|
+
@id_token_claims ||= JSON::JWT.decode(id_token, :skip_verification)
|
|
55
81
|
end
|
|
56
82
|
|
|
57
83
|
def prune!(hash)
|
|
@@ -69,7 +95,7 @@ module OmniAuth
|
|
|
69
95
|
:headers => {'Authorization' => HTTPAuth::Basic.pack_authorization(client.id, client.secret)}
|
|
70
96
|
}
|
|
71
97
|
|
|
72
|
-
client.get_token(token_params)
|
|
98
|
+
client.get_token(token_params)
|
|
73
99
|
end
|
|
74
100
|
|
|
75
101
|
def callback_url
|
data/omniauth-yahoojp.gemspec
CHANGED
|
@@ -4,8 +4,8 @@ require File.expand_path('../lib/omniauth-yahoojp/version', __FILE__)
|
|
|
4
4
|
Gem::Specification.new do |gem|
|
|
5
5
|
gem.authors = ["mikanmarusan"]
|
|
6
6
|
gem.email = ["chiakifujimon@gmail.com"]
|
|
7
|
-
gem.description = %q{
|
|
8
|
-
gem.summary = %q{
|
|
7
|
+
gem.description = %q{OmniAuth strategy for Yahoo! JAPAN.}
|
|
8
|
+
gem.summary = %q{OmniAuth strategy for Yahoo! JAPAN.}
|
|
9
9
|
gem.homepage = "https://github.com/mikanmarusan/omniauth-yahoojp"
|
|
10
10
|
|
|
11
11
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
@@ -14,12 +14,13 @@ Gem::Specification.new do |gem|
|
|
|
14
14
|
gem.name = "omniauth-yahoojp"
|
|
15
15
|
gem.require_paths = ["lib"]
|
|
16
16
|
gem.version = OmniAuth::YahooJp::VERSION
|
|
17
|
-
gem.licenses = "MIT"
|
|
17
|
+
gem.licenses = ["MIT"]
|
|
18
18
|
|
|
19
|
-
gem.add_dependency 'omniauth', '
|
|
20
|
-
gem.add_dependency 'omniauth-oauth2', '
|
|
19
|
+
gem.add_dependency 'omniauth', '>= 1.0'
|
|
20
|
+
gem.add_dependency 'omniauth-oauth2', '>= 1.1'
|
|
21
21
|
gem.add_dependency 'httpauth'
|
|
22
|
-
gem.
|
|
22
|
+
gem.add_dependency 'json-jwt', '>= 1.16.6'
|
|
23
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
|
23
24
|
gem.add_development_dependency 'rack-test'
|
|
24
25
|
gem.add_development_dependency 'simplecov'
|
|
25
26
|
gem.add_development_dependency 'webmock'
|
|
@@ -1,23 +1,289 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'omniauth-yahoojp'
|
|
3
|
+
require 'json/jwt'
|
|
3
4
|
|
|
4
|
-
describe OmniAuth::Strategies::YahooJp do
|
|
5
|
+
RSpec.describe OmniAuth::Strategies::YahooJp do
|
|
6
|
+
let(:app) { lambda { |_env| [200, {}, ['Hello']] } }
|
|
7
|
+
let(:strategy) { described_class.new(app, 'client_id', 'client_secret') }
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
describe 'client options' do
|
|
10
|
+
it 'has correct site' do
|
|
11
|
+
expect(strategy.options.client_options.site).to eq('https://auth.login.yahoo.co.jp')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'has correct authorize url' do
|
|
15
|
+
expect(strategy.options.client_options.authorize_url).to eq('/yconnect/v2/authorization')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'has correct token url' do
|
|
19
|
+
expect(strategy.options.client_options.token_url).to eq('/yconnect/v2/token')
|
|
20
|
+
end
|
|
8
21
|
end
|
|
9
22
|
|
|
10
|
-
|
|
11
|
-
it '
|
|
12
|
-
|
|
23
|
+
describe 'default options' do
|
|
24
|
+
it 'has userinfo_access enabled by default' do
|
|
25
|
+
expect(strategy.options.userinfo_access).to be true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'with access_token' do
|
|
30
|
+
let(:jwt_payload) { { 'sub' => 'test123', 'name' => 'Test User', 'email' => 'test@example.com' } }
|
|
31
|
+
let(:jwt_string) { JSON::JWT.new(jwt_payload).to_s }
|
|
32
|
+
let(:access_token) do
|
|
33
|
+
instance_double(
|
|
34
|
+
OAuth2::AccessToken,
|
|
35
|
+
token: 'mock_token',
|
|
36
|
+
refresh_token: 'mock_refresh',
|
|
37
|
+
expires?: true,
|
|
38
|
+
expires_at: 1234567890,
|
|
39
|
+
params: { 'id_token' => jwt_string },
|
|
40
|
+
options: {}
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
before do
|
|
45
|
+
allow(strategy).to receive(:access_token).and_return(access_token)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#id_token' do
|
|
49
|
+
it 'returns the id_token from access_token params' do
|
|
50
|
+
expect(strategy.id_token).to eq(jwt_string)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'returns nil when no id_token in params' do
|
|
54
|
+
allow(access_token).to receive(:params).and_return({})
|
|
55
|
+
expect(strategy.id_token).to be_nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'returns nil when id_token is empty string' do
|
|
59
|
+
allow(access_token).to receive(:params).and_return({ 'id_token' => '' })
|
|
60
|
+
expect(strategy.id_token).to be_nil
|
|
61
|
+
end
|
|
13
62
|
end
|
|
14
63
|
|
|
15
|
-
|
|
16
|
-
|
|
64
|
+
describe '#id_token_claims' do
|
|
65
|
+
it 'decodes the JWT without verification' do
|
|
66
|
+
claims = strategy.id_token_claims
|
|
67
|
+
expect(claims['sub']).to eq('test123')
|
|
68
|
+
expect(claims['name']).to eq('Test User')
|
|
69
|
+
expect(claims['email']).to eq('test@example.com')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'memoizes the result' do
|
|
73
|
+
first_call = strategy.id_token_claims
|
|
74
|
+
second_call = strategy.id_token_claims
|
|
75
|
+
expect(first_call).to equal(second_call)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'returns nil when id_token is nil' do
|
|
79
|
+
allow(access_token).to receive(:params).and_return({})
|
|
80
|
+
expect(strategy.id_token_claims).to be_nil
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'raises on malformed id_token' do
|
|
84
|
+
allow(access_token).to receive(:params).and_return({ 'id_token' => 'not-a-jwt' })
|
|
85
|
+
expect { strategy.id_token_claims }.to raise_error(JSON::JWT::InvalidFormat)
|
|
86
|
+
end
|
|
17
87
|
end
|
|
18
88
|
|
|
19
|
-
|
|
20
|
-
|
|
89
|
+
describe '#raw_info' do
|
|
90
|
+
context 'with userinfo_access: true' do
|
|
91
|
+
let(:userinfo_response) do
|
|
92
|
+
instance_double(OAuth2::Response, parsed: {
|
|
93
|
+
'sub' => 'user456',
|
|
94
|
+
'name' => 'Yahoo User',
|
|
95
|
+
'email' => 'yahoo@example.com',
|
|
96
|
+
'address' => { 'country' => 'JP' }
|
|
97
|
+
})
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
before do
|
|
101
|
+
allow(access_token).to receive(:get)
|
|
102
|
+
.with('https://userinfo.yahooapis.jp/yconnect/v2/attribute')
|
|
103
|
+
.and_return(userinfo_response)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'calls the UserInfo API' do
|
|
107
|
+
strategy.raw_info
|
|
108
|
+
expect(access_token).to have_received(:get)
|
|
109
|
+
.with('https://userinfo.yahooapis.jp/yconnect/v2/attribute')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'sets access_token mode to header' do
|
|
113
|
+
strategy.raw_info
|
|
114
|
+
expect(access_token.options[:mode]).to eq(:header)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'returns parsed UserInfo response' do
|
|
118
|
+
expect(strategy.raw_info['sub']).to eq('user456')
|
|
119
|
+
expect(strategy.raw_info['name']).to eq('Yahoo User')
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context 'with userinfo_access: false and id_token present' do
|
|
124
|
+
before do
|
|
125
|
+
strategy.options[:userinfo_access] = false
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'returns id_token_claims' do
|
|
129
|
+
expect(strategy.raw_info['sub']).to eq('test123')
|
|
130
|
+
expect(strategy.raw_info['name']).to eq('Test User')
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'does not call the UserInfo API' do
|
|
134
|
+
expect(access_token).not_to receive(:get)
|
|
135
|
+
strategy.raw_info
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
context 'with userinfo_access: false and no id_token' do
|
|
140
|
+
before do
|
|
141
|
+
strategy.options[:userinfo_access] = false
|
|
142
|
+
allow(access_token).to receive(:params).and_return({})
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'returns empty hash' do
|
|
146
|
+
expect(strategy.raw_info).to eq({})
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe '#info' do
|
|
152
|
+
let(:full_profile) do
|
|
153
|
+
{
|
|
154
|
+
'sub' => 'user456',
|
|
155
|
+
'name' => 'Yahoo User',
|
|
156
|
+
'given_name' => 'Taro',
|
|
157
|
+
'given_name#ja-Kana-JP' => 'タロウ',
|
|
158
|
+
'given_name#ja-Hani-JP' => '太郎',
|
|
159
|
+
'family_name' => 'Yamada',
|
|
160
|
+
'family_name#ja-Kana-JP' => 'ヤマダ',
|
|
161
|
+
'family_name#ja-Hani-JP' => '山田',
|
|
162
|
+
'gender' => 'male',
|
|
163
|
+
'zoneinfo' => 'Asia/Tokyo',
|
|
164
|
+
'locale' => 'ja-JP',
|
|
165
|
+
'birthdate' => '1990-01-01',
|
|
166
|
+
'nickname' => 'taro',
|
|
167
|
+
'picture' => 'https://example.com/photo.jpg',
|
|
168
|
+
'email' => 'taro@example.com',
|
|
169
|
+
'email_verified' => true,
|
|
170
|
+
'address' => { 'country' => 'JP', 'region' => 'Tokyo' }
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
let(:userinfo_response) do
|
|
174
|
+
instance_double(OAuth2::Response, parsed: full_profile)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
before do
|
|
178
|
+
allow(access_token).to receive(:get)
|
|
179
|
+
.with('https://userinfo.yahooapis.jp/yconnect/v2/attribute')
|
|
180
|
+
.and_return(userinfo_response)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'maps all standard fields' do
|
|
184
|
+
info = strategy.info
|
|
185
|
+
expect(info[:sub]).to eq('user456')
|
|
186
|
+
expect(info[:name]).to eq('Yahoo User')
|
|
187
|
+
expect(info[:given_name]).to eq('Taro')
|
|
188
|
+
expect(info[:family_name]).to eq('Yamada')
|
|
189
|
+
expect(info[:email]).to eq('taro@example.com')
|
|
190
|
+
expect(info[:nickname]).to eq('taro')
|
|
191
|
+
expect(info[:picture]).to eq('https://example.com/photo.jpg')
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'maps Japanese locale-specific fields' do
|
|
195
|
+
info = strategy.info
|
|
196
|
+
expect(info[:given_name_ja_kana_jp]).to eq('タロウ')
|
|
197
|
+
expect(info[:given_name_ja_hani_jp]).to eq('太郎')
|
|
198
|
+
expect(info[:family_name_ja_kana_jp]).to eq('ヤマダ')
|
|
199
|
+
expect(info[:family_name_ja_hani_jp]).to eq('山田')
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'maps address as nested hash' do
|
|
203
|
+
info = strategy.info
|
|
204
|
+
expect(info[:address]['country']).to eq('JP')
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'prunes nil values' do
|
|
208
|
+
allow(userinfo_response).to receive(:parsed).and_return({ 'sub' => 'user456' })
|
|
209
|
+
info = strategy.info
|
|
210
|
+
expect(info).not_to have_key(:name)
|
|
211
|
+
expect(info).not_to have_key(:email)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe '#uid' do
|
|
216
|
+
context 'with userinfo_access: true' do
|
|
217
|
+
let(:userinfo_response) do
|
|
218
|
+
instance_double(OAuth2::Response, parsed: { 'sub' => 'user456' })
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
before do
|
|
222
|
+
allow(access_token).to receive(:get)
|
|
223
|
+
.with('https://userinfo.yahooapis.jp/yconnect/v2/attribute')
|
|
224
|
+
.and_return(userinfo_response)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'returns sub from UserInfo' do
|
|
228
|
+
expect(strategy.uid).to eq('user456')
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context 'with userinfo_access: false' do
|
|
233
|
+
before do
|
|
234
|
+
strategy.options[:userinfo_access] = false
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'returns sub from id_token' do
|
|
238
|
+
expect(strategy.uid).to eq('test123')
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe '#credentials' do
|
|
244
|
+
it 'includes token' do
|
|
245
|
+
expect(strategy.credentials['token']).to eq('mock_token')
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'includes refresh_token' do
|
|
249
|
+
expect(strategy.credentials['refresh_token']).to eq('mock_refresh')
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'includes expires_at' do
|
|
253
|
+
expect(strategy.credentials['expires_at']).to eq(1234567890)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it 'includes expires flag' do
|
|
257
|
+
expect(strategy.credentials['expires']).to be true
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
it 'includes id_token' do
|
|
261
|
+
expect(strategy.credentials['id_token']).to eq(jwt_string)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it 'omits id_token when not present' do
|
|
265
|
+
allow(access_token).to receive(:params).and_return({})
|
|
266
|
+
expect(strategy.credentials).not_to have_key('id_token')
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
describe '#extra' do
|
|
271
|
+
before do
|
|
272
|
+
strategy.options[:userinfo_access] = false
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'includes id_token' do
|
|
276
|
+
expect(strategy.extra[:id_token]).to eq(jwt_string)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'includes id_token_claims' do
|
|
280
|
+
claims = strategy.extra[:id_token_claims]
|
|
281
|
+
expect(claims['sub']).to eq('test123')
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it 'includes raw_info' do
|
|
285
|
+
expect(strategy.extra[:raw_info]).not_to be_nil
|
|
286
|
+
end
|
|
21
287
|
end
|
|
22
288
|
end
|
|
23
289
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,122 +1,139 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omniauth-yahoojp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- mikanmarusan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: omniauth
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '1.0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: omniauth-oauth2
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '1.1'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '1.1'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: httpauth
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: json-jwt
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 1.16.6
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.16.6
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rspec
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
|
-
- - ~>
|
|
73
|
+
- - "~>"
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
75
|
+
version: '3.0'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
|
-
- - ~>
|
|
80
|
+
- - "~>"
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
82
|
+
version: '3.0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: rack-test
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
72
86
|
requirements:
|
|
73
|
-
- -
|
|
87
|
+
- - ">="
|
|
74
88
|
- !ruby/object:Gem::Version
|
|
75
89
|
version: '0'
|
|
76
90
|
type: :development
|
|
77
91
|
prerelease: false
|
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
93
|
requirements:
|
|
80
|
-
- -
|
|
94
|
+
- - ">="
|
|
81
95
|
- !ruby/object:Gem::Version
|
|
82
96
|
version: '0'
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
98
|
name: simplecov
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
86
100
|
requirements:
|
|
87
|
-
- -
|
|
101
|
+
- - ">="
|
|
88
102
|
- !ruby/object:Gem::Version
|
|
89
103
|
version: '0'
|
|
90
104
|
type: :development
|
|
91
105
|
prerelease: false
|
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
107
|
requirements:
|
|
94
|
-
- -
|
|
108
|
+
- - ">="
|
|
95
109
|
- !ruby/object:Gem::Version
|
|
96
110
|
version: '0'
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: webmock
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
100
114
|
requirements:
|
|
101
|
-
- -
|
|
115
|
+
- - ">="
|
|
102
116
|
- !ruby/object:Gem::Version
|
|
103
117
|
version: '0'
|
|
104
118
|
type: :development
|
|
105
119
|
prerelease: false
|
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
121
|
requirements:
|
|
108
|
-
- -
|
|
122
|
+
- - ">="
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
124
|
version: '0'
|
|
111
|
-
description:
|
|
125
|
+
description: OmniAuth strategy for Yahoo! JAPAN.
|
|
112
126
|
email:
|
|
113
127
|
- chiakifujimon@gmail.com
|
|
114
128
|
executables: []
|
|
115
129
|
extensions: []
|
|
116
130
|
extra_rdoc_files: []
|
|
117
131
|
files:
|
|
118
|
-
- .
|
|
119
|
-
- .
|
|
132
|
+
- ".github/workflows/claude-code-review.yml"
|
|
133
|
+
- ".github/workflows/claude.yml"
|
|
134
|
+
- ".gitignore"
|
|
135
|
+
- ".rspec"
|
|
136
|
+
- CLAUDE.md
|
|
120
137
|
- Gemfile
|
|
121
138
|
- Guardfile
|
|
122
139
|
- README.md
|
|
@@ -137,20 +154,19 @@ require_paths:
|
|
|
137
154
|
- lib
|
|
138
155
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
156
|
requirements:
|
|
140
|
-
- -
|
|
157
|
+
- - ">="
|
|
141
158
|
- !ruby/object:Gem::Version
|
|
142
159
|
version: '0'
|
|
143
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
161
|
requirements:
|
|
145
|
-
- -
|
|
162
|
+
- - ">="
|
|
146
163
|
- !ruby/object:Gem::Version
|
|
147
164
|
version: '0'
|
|
148
165
|
requirements: []
|
|
149
|
-
|
|
150
|
-
rubygems_version: 2.0.14.1
|
|
166
|
+
rubygems_version: 3.0.3.1
|
|
151
167
|
signing_key:
|
|
152
168
|
specification_version: 4
|
|
153
|
-
summary:
|
|
169
|
+
summary: OmniAuth strategy for Yahoo! JAPAN.
|
|
154
170
|
test_files:
|
|
155
171
|
- spec/omniauth/strategies/yahoojp_spec.rb
|
|
156
172
|
- spec/spec_helper.rb
|