omniauth-sps_commerce 0.1.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 +7 -0
- data/CHANGELOG.md +19 -0
- data/LICENSE.txt +21 -0
- data/README.md +102 -0
- data/lib/omniauth/strategies/sps_commerce.rb +118 -0
- data/lib/omniauth-sps_commerce/version.rb +7 -0
- data/lib/omniauth-sps_commerce.rb +4 -0
- data/omniauth-sps_commerce.gemspec +38 -0
- metadata +87 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0acb9eeb0bc851072a548e41b2eba2c6147e3adcc8f37212f989db855dc1d033
|
|
4
|
+
data.tar.gz: 90faa4b21c306e2e962299fa98399992d5adcb4205029e4cb37fad344e817c1f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '0775910b5083a680d252ba95a4686be5aee85edc53451a5c7f3d14c29b14fe8cb80b568be466865302776d8e409cd3d682a6f15000a7cd99b639fcb768b69244'
|
|
7
|
+
data.tar.gz: 485b917d28bf009fec063639f78d87ac91ec7e40bcb6d1b0a6b4b9a5945759abe96b1109377da03f07af761f059662d43706e28928897e236d2637885cb06597
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `OmniAuth::Strategies::SpsCommerce`, registered as `:sps_commerce`: the authorization code
|
|
10
|
+
flow against `auth.spscommerce.com` (`/authorize`, `/oauth/token`), with a JSON token
|
|
11
|
+
request carrying the client credentials in its body.
|
|
12
|
+
- Default scope `openid profile email offline_access` and default audience
|
|
13
|
+
`https://spscommerce.com`, so the callback returns an API access token and a refresh token.
|
|
14
|
+
- `uid` and `info` from the id_token, falling back to the access token's claims; `extra`
|
|
15
|
+
carries both claim sets and the token response params (without the raw id_token).
|
|
16
|
+
- Per-request `prompt` and `login_hint`.
|
|
17
|
+
- A `callback_url` override that drops the callback's query string and honors a configured
|
|
18
|
+
`:callback_url`.
|
|
19
|
+
- Supports `omniauth-oauth2` 1.8 as well as 1.9, so apps still on 1.8 can use it.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dropstream
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# OmniAuth SPS Commerce
|
|
2
|
+
|
|
3
|
+
An OmniAuth strategy for [SPS Commerce](https://www.spscommerce.com). It runs the OAuth 2.0
|
|
4
|
+
authorization code flow against `auth.spscommerce.com` (SPS's Auth0 tenant) and returns an
|
|
5
|
+
access token and refresh token for the SPS APIs, such as the Transaction API.
|
|
6
|
+
|
|
7
|
+
Requires Ruby >= 3.2, OmniAuth 2.x and `omniauth-oauth2` 1.8 or 1.9.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'omniauth-sps_commerce'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
OmniAuth 2 only accepts `POST` for the request phase. In a Rails app, add
|
|
18
|
+
[`omniauth-rails_csrf_protection`](https://github.com/cookpad/omniauth-rails_csrf_protection)
|
|
19
|
+
and link to the provider with `button_to`.
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
|
23
|
+
provider :sps_commerce, ENV['SPS_CLIENT_ID'], ENV['SPS_CLIENT_SECRET']
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Register the callback URL (`https://<host>/auth/sps_commerce/callback`) on the app in the
|
|
28
|
+
SPS Dev Center.
|
|
29
|
+
|
|
30
|
+
### Production and sandbox keys
|
|
31
|
+
|
|
32
|
+
Each SPS app comes with a production key and a sandbox key. Both authenticate against
|
|
33
|
+
`auth.spscommerce.com`, so register the strategy once per key under different names:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
|
37
|
+
provider :sps_commerce, ENV['SPS_CLIENT_ID'], ENV['SPS_CLIENT_SECRET']
|
|
38
|
+
provider :sps_commerce, ENV['SPS_SANDBOX_CLIENT_ID'], ENV['SPS_SANDBOX_CLIENT_SECRET'],
|
|
39
|
+
name: :sps_commerce_sandbox
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The sandbox registration answers on `/auth/sps_commerce_sandbox` and
|
|
44
|
+
`/auth/sps_commerce_sandbox/callback`. A refresh token can only be redeemed with the key
|
|
45
|
+
that issued it, so record which registration a token came from (`auth.provider`).
|
|
46
|
+
|
|
47
|
+
Use a separate SPS app (and so separate keys) per deployment environment.
|
|
48
|
+
|
|
49
|
+
## The auth hash
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
auth = request.env['omniauth.auth']
|
|
53
|
+
auth['provider'] # "sps_commerce" or "sps_commerce_sandbox"
|
|
54
|
+
auth['uid'] # Auth0 subject of the SPS user who authorized
|
|
55
|
+
auth['info'] # name, email, nickname (from the id_token)
|
|
56
|
+
auth['credentials']['token'] # access token
|
|
57
|
+
auth['credentials']['refresh_token']
|
|
58
|
+
auth['credentials']['expires_at']
|
|
59
|
+
auth['extra']['claims'] # id_token claims
|
|
60
|
+
auth['extra']['access_token_claims']# access token claims, including SPS-specific ones
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Token claims are decoded without verifying signatures. That is safe only because tokens
|
|
64
|
+
come straight from `auth.spscommerce.com` over TLS, never from the browser. Don't reuse the
|
|
65
|
+
decoder on tokens from any other source.
|
|
66
|
+
|
|
67
|
+
## Configuring
|
|
68
|
+
|
|
69
|
+
| Option | Default | Notes |
|
|
70
|
+
|--------|---------|-------|
|
|
71
|
+
| `scope` | `openid profile email offline_access` | `offline_access` is what returns a refresh token. |
|
|
72
|
+
| `audience` | `https://spscommerce.com` | Without an audience, Auth0 issues an opaque token that only works on `/userinfo`. |
|
|
73
|
+
| `client_options[:site]` | `https://auth.spscommerce.com` | |
|
|
74
|
+
| `callback_url` | derived from the request | Drops the callback's query string, since Auth0 requires an exact `redirect_uri` match. |
|
|
75
|
+
|
|
76
|
+
`prompt` and `login_hint` can also be set per request (`/auth/sps_commerce?login_hint=…`).
|
|
77
|
+
Nothing else is taken from request params.
|
|
78
|
+
|
|
79
|
+
The endpoints come from
|
|
80
|
+
[SPS's OpenID configuration](https://auth.spscommerce.com/.well-known/openid-configuration).
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
Run `bin/setup`, then `bundle exec rake spec`. Run `bundle exec bundle-audit check --update`
|
|
85
|
+
to check the locked dependencies against the advisory database; CI runs it weekly.
|
|
86
|
+
|
|
87
|
+
## Releasing
|
|
88
|
+
|
|
89
|
+
Releases are cut from the GitHub Releases UI and published by the `Release` workflow
|
|
90
|
+
through [RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/):
|
|
91
|
+
|
|
92
|
+
1. Bump `VERSION` in `lib/omniauth-sps_commerce/version.rb` and add a `CHANGELOG.md`
|
|
93
|
+
section. Commit both on `main`.
|
|
94
|
+
2. Draft a release targeting `main` with tag `vX.Y.Z` matching `version.rb`, then publish.
|
|
95
|
+
|
|
96
|
+
One-time setup on rubygems.org: open the gem, then **Trusted publishers** → **Create**, with
|
|
97
|
+
owner `dropstream`, repository `omniauth-sps_commerce`, workflow `release.yml` and environment
|
|
98
|
+
`release`. The repo also needs an environment named `release`.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
Available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'omniauth-oauth2'
|
|
5
|
+
|
|
6
|
+
module OmniAuth
|
|
7
|
+
module Strategies
|
|
8
|
+
# SPS Commerce identity runs on Auth0. The endpoints below come from
|
|
9
|
+
# https://auth.spscommerce.com/.well-known/openid-configuration.
|
|
10
|
+
#
|
|
11
|
+
# An SPS app has a production key and a sandbox key. Both authenticate against
|
|
12
|
+
# the same host, so the strategy does not need to know which one it holds:
|
|
13
|
+
# register it twice with different names to offer both (see the README).
|
|
14
|
+
class SpsCommerce < OmniAuth::Strategies::OAuth2
|
|
15
|
+
DEFAULT_SITE = 'https://auth.spscommerce.com'
|
|
16
|
+
# The audience SPS documents for the authorize request. Without one, Auth0
|
|
17
|
+
# issues an opaque access token that only works on /userinfo.
|
|
18
|
+
DEFAULT_AUDIENCE = 'https://spscommerce.com'
|
|
19
|
+
# offline_access is what makes Auth0 return a refresh token.
|
|
20
|
+
DEFAULT_SCOPE = 'openid profile email offline_access'
|
|
21
|
+
|
|
22
|
+
option :name, 'sps_commerce'
|
|
23
|
+
|
|
24
|
+
option :client_options, {
|
|
25
|
+
site: DEFAULT_SITE,
|
|
26
|
+
authorize_url: '/authorize',
|
|
27
|
+
token_url: '/oauth/token',
|
|
28
|
+
# SPS documents client_id and client_secret in the token request body.
|
|
29
|
+
auth_scheme: :request_body
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
option :scope, DEFAULT_SCOPE
|
|
33
|
+
option :audience, DEFAULT_AUDIENCE
|
|
34
|
+
|
|
35
|
+
option :authorize_options, %i[scope audience prompt login_hint]
|
|
36
|
+
|
|
37
|
+
# Options a request may set for itself, e.g.
|
|
38
|
+
# /auth/sps_commerce?login_hint=user@example.com
|
|
39
|
+
REQUEST_AUTHORIZE_OPTIONS = %w[prompt login_hint].freeze
|
|
40
|
+
|
|
41
|
+
uid { user_claims['sub'] }
|
|
42
|
+
|
|
43
|
+
info do
|
|
44
|
+
{
|
|
45
|
+
name: user_claims['name'],
|
|
46
|
+
email: user_claims['email'],
|
|
47
|
+
nickname: user_claims['nickname']
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
extra do
|
|
52
|
+
{
|
|
53
|
+
'params' => access_token.params.except('id_token'),
|
|
54
|
+
'claims' => user_claims,
|
|
55
|
+
'access_token_claims' => access_token_claims
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def authorize_params
|
|
60
|
+
super.tap do |params|
|
|
61
|
+
REQUEST_AUTHORIZE_OPTIONS.each do |key|
|
|
62
|
+
value = request.params[key]
|
|
63
|
+
params[key.to_sym] = value unless value.nil? || value == ''
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# SPS documents a JSON token request; oauth2 sends a form unless the token
|
|
69
|
+
# params carry this header. It is added here rather than through the
|
|
70
|
+
# token_params option, which would symbolize the header name, and oauth2
|
|
71
|
+
# only recognizes it as a string.
|
|
72
|
+
def build_access_token
|
|
73
|
+
client.auth_code.get_token(
|
|
74
|
+
request.params['code'],
|
|
75
|
+
{ redirect_uri: callback_url, headers: { 'Content-Type' => 'application/json' } }
|
|
76
|
+
.merge(token_params.to_hash(symbolize_keys: true)),
|
|
77
|
+
deep_symbolize(options.auth_token_params)
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# OmniAuth::Strategy#callback_url appends the callback request's own query
|
|
82
|
+
# string, and Auth0 requires redirect_uri to match an allowed callback URL
|
|
83
|
+
# exactly. omniauth 2's `callback_path` already carries SCRIPT_NAME, so mount
|
|
84
|
+
# prefixes must not be added again.
|
|
85
|
+
def callback_url
|
|
86
|
+
options[:callback_url] || (full_host + callback_path)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Claims for the signed-in user: from the id_token (granted by the openid
|
|
92
|
+
# scope), otherwise from the access token. The payload is read without
|
|
93
|
+
# verifying the signature, which is acceptable only because the token
|
|
94
|
+
# arrives directly from auth.spscommerce.com over TLS, never from the browser.
|
|
95
|
+
def user_claims
|
|
96
|
+
@user_claims ||= decode_jwt_claims(access_token.params['id_token']) || access_token_claims
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# The API access token's claims, which carry the SPS-specific ones (for
|
|
100
|
+
# example the organization). Empty when the token is opaque.
|
|
101
|
+
def access_token_claims
|
|
102
|
+
@access_token_claims ||= decode_jwt_claims(access_token.token) || {}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def decode_jwt_claims(jwt)
|
|
106
|
+
payload = jwt.to_s.split('.')[1]
|
|
107
|
+
return nil if payload.nil? || payload.empty?
|
|
108
|
+
|
|
109
|
+
# Base64url-decode by hand; the base64 gem left Ruby's default gems in 3.4.
|
|
110
|
+
json = (payload.tr('-_', '+/') + '=' * (-payload.length % 4)).unpack1('m')
|
|
111
|
+
claims = JSON.parse(json)
|
|
112
|
+
claims.is_a?(Hash) ? claims : nil
|
|
113
|
+
rescue ArgumentError, JSON::ParserError, EncodingError
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require "omniauth-sps_commerce/version"
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = "omniauth-sps_commerce"
|
|
9
|
+
spec.version = Omniauth::SpsCommerce::VERSION
|
|
10
|
+
spec.authors = ["Karl Falconer"]
|
|
11
|
+
spec.email = ["karl.falconer@getdropstream.com"]
|
|
12
|
+
|
|
13
|
+
spec.summary = "OmniAuth strategy for SPS Commerce"
|
|
14
|
+
spec.description = "An OmniAuth OAuth2 strategy that authenticates against SPS Commerce " \
|
|
15
|
+
"(auth.spscommerce.com) and obtains tokens for the SPS Commerce APIs."
|
|
16
|
+
spec.homepage = "https://github.com/dropstream/omniauth-sps_commerce"
|
|
17
|
+
spec.license = "MIT"
|
|
18
|
+
|
|
19
|
+
spec.required_ruby_version = ">= 3.2"
|
|
20
|
+
|
|
21
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
23
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
24
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
25
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
26
|
+
|
|
27
|
+
# Ship only the library itself; development scaffolding stays out of the gem.
|
|
28
|
+
spec.files = Dir.chdir(__dir__) do
|
|
29
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
30
|
+
f.match(%r{\A(?:spec|bin|pkg|\.github)/}) ||
|
|
31
|
+
f.match(%r{\A(?:\.gitignore|\.rspec|\.ruby-version|\.ruby-gemset|Gemfile|Gemfile\.lock|Rakefile)\z})
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
spec.require_paths = ["lib"]
|
|
35
|
+
|
|
36
|
+
spec.add_dependency "omniauth", "~> 2.0"
|
|
37
|
+
spec.add_dependency "omniauth-oauth2", ">= 1.8", "< 2"
|
|
38
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: omniauth-sps_commerce
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Karl Falconer
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: omniauth
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: omniauth-oauth2
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.8'
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '2'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '1.8'
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '2'
|
|
46
|
+
description: An OmniAuth OAuth2 strategy that authenticates against SPS Commerce (auth.spscommerce.com)
|
|
47
|
+
and obtains tokens for the SPS Commerce APIs.
|
|
48
|
+
email:
|
|
49
|
+
- karl.falconer@getdropstream.com
|
|
50
|
+
executables: []
|
|
51
|
+
extensions: []
|
|
52
|
+
extra_rdoc_files: []
|
|
53
|
+
files:
|
|
54
|
+
- CHANGELOG.md
|
|
55
|
+
- LICENSE.txt
|
|
56
|
+
- README.md
|
|
57
|
+
- lib/omniauth-sps_commerce.rb
|
|
58
|
+
- lib/omniauth-sps_commerce/version.rb
|
|
59
|
+
- lib/omniauth/strategies/sps_commerce.rb
|
|
60
|
+
- omniauth-sps_commerce.gemspec
|
|
61
|
+
homepage: https://github.com/dropstream/omniauth-sps_commerce
|
|
62
|
+
licenses:
|
|
63
|
+
- MIT
|
|
64
|
+
metadata:
|
|
65
|
+
allowed_push_host: https://rubygems.org
|
|
66
|
+
homepage_uri: https://github.com/dropstream/omniauth-sps_commerce
|
|
67
|
+
source_code_uri: https://github.com/dropstream/omniauth-sps_commerce
|
|
68
|
+
changelog_uri: https://github.com/dropstream/omniauth-sps_commerce/blob/main/CHANGELOG.md
|
|
69
|
+
rubygems_mfa_required: 'true'
|
|
70
|
+
rdoc_options: []
|
|
71
|
+
require_paths:
|
|
72
|
+
- lib
|
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
|
+
requirements:
|
|
75
|
+
- - ">="
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '3.2'
|
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
requirements: []
|
|
84
|
+
rubygems_version: 3.6.9
|
|
85
|
+
specification_version: 4
|
|
86
|
+
summary: OmniAuth strategy for SPS Commerce
|
|
87
|
+
test_files: []
|