Skip to content

Commit 9b01ea7

Browse files
committed
Add support for customer login
* Add instance method on Customer object to generate a login token for that customer. This only works if the app has the store_v2_customer_login scope and is installed on the store.
1 parent 62a84f5 commit 9b01ea7

File tree

10 files changed

+86
-11
lines changed

10 files changed

+86
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ pkg/*
1515
tmp/*
1616
.env
1717
.env-*
18+
vendor/bundle

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Your contribution here.
33

44
* [#000](https://github.com/bigcommerce/bigcommerce-api-ruby/pull/000): Brief description here. - [@username](https://github.com/username).
5+
* [#128](https://github.com/bigcommerce/bigcommerce-api-ruby/pull/128): Added support for token generation for storefront login. - [@mattolson](https://github.com/mattolson).
56

67
## 1.0.0
78
Please note that this is the start of a new major release which breaks all backward compatibility.

CONTRIBUTING.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Contributing to Bigcommerce
22

3-
4-
We would love to see contributors! You're encouraged to submit [pull requests](https://github.com/bigcommerce/bigcommerce-api-ruby/pulls), [propose features, and discuss issues](https://github.com/bigcommerce/bigcommerce-api-ruby/issues).
3+
We welcome your contribution! You're encouraged to submit [pull requests](https://github.com/bigcommerce/bigcommerce-api-ruby/pulls), [propose features, and discuss issues](https://github.com/bigcommerce/bigcommerce-api-ruby/issues).
54

65
#### Fork the Project
76

DEPENDENCIES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ Many thanks to the contributors and authors of the following libraries!
55
- [Faraday](https://github.com/lostisland/faraday) Simple, but flexible HTTP client library, with support for multiple backends. - [MIT](https://github.com/lostisland/faraday/blob/master/LICENSE.md)
66
- [Faraday Middleware](https://github.com/lostisland/faraday_middleware) Various Faraday middlewares for Faraday-based API wrappers. - [MIT](https://github.com/lostisland/faraday_middleware/blob/master/LICENSE.md)
77
- [Hashie](https://github.com/intridea/hashie) Hashie is a collection of classes and mixins that make hashes more powerful. - [MIT](https://github.com/intridea/hashie/blob/master/LICENSE)
8+
- [JWT](https://github.com/jwt/ruby-jwt) Used to encode and sign JWT tokens for the Customer Login API. - [MIT](https://github.com/jwt/ruby-jwt/blob/master/LICENSE)

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ For more information about configuring SSL with Faraday, please see the followin
9292
- [Faraday SSL example](https://gist.github.com/mislav/938183)
9393
- [Faraday: Setting up SSL certificates](https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates)
9494

95+
### Customer Login API
96+
If you want to generate tokens for storefront login using the Customer Login API, you need to configure your app's client secret.
97+
98+
- ```store_hash```: The store hash of the store you are operating against.
99+
- ```client_id```: Obtained from the on the BigCommerce [Developer Portal's](http://developer.bigcommerce.com) "My Apps" section.
100+
- ```client_secret```: Obtained from the on the BigCommerce [Developer Portal's](http://developer.bigcommerce.com) "My Apps" section.
101+
102+
```rb
103+
Bigcommerce.configure do |config|
104+
config.store_hash = ENV['BC_STORE_HASH']
105+
config.client_id = ENV['BC_CLIENT_ID']
106+
config.client_secret = ENV['BC_CLIENT_SECRET']
107+
end
108+
```
95109

96110
## Usage
97111
For full examples of using the API client, please see the [examples folder](examples) and refer to BigCommerce's [developer documentation](https://developer.bigcommerce.com/api).
@@ -124,8 +138,8 @@ This connection is nothing more than a `Faraday::Connection` – so if you want
124138
```rb
125139
connection = Bigcommerce::Connection.build(
126140
Bigcommerce::Config.new(
127-
store_hash: ENV['BC_STORE_HASH'],
128-
client_id: ENV['BC_CLIENT_ID'],
141+
store_hash: ENV['BC_STORE_HASH'],
142+
client_id: ENV['BC_CLIENT_ID'],
129143
access_token: ENV['BC_ACCESS_TOKEN']
130144
)
131145
)
@@ -143,7 +157,7 @@ Bigcommerce::System.raw_request(:get, 'time', connection: connection)
143157
```rb
144158
connection_legacy = Bigcommerce::Connection.build(
145159
Bigcommerce::Config.new(
146-
auth: 'legacy',
160+
auth: 'legacy',
147161
url: ENV['BC_API_ENDPOINT_LEGACY'],
148162
username: ENV['BC_USERNAME'],
149163
api_key: ENV['BC_API_KEY']
@@ -159,4 +173,4 @@ Bigcommerce::System.raw_request(:get, 'time', connection: connection_legacy)
159173
```
160174

161175
## Contributing
162-
See [CONTRIBUTING.md](CONTRIBUTING.md)
176+
See [CONTRIBUTING.md](CONTRIBUTING.md)

bigcommerce.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
2323
s.add_dependency 'faraday', '~> 0.9'
2424
s.add_dependency 'faraday_middleware', '~> 0.10.0'
2525
s.add_dependency 'hashie', '~> 3.4'
26+
s.add_dependency 'jwt', '~> 1.5.4'
2627
end

examples/customers/customer_login.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
require 'bigcommerce'
2+
3+
Bigcommerce.configure do |config|
4+
config.store_hash = ENV['BC_STORE_HASH']
5+
config.client_id = ENV['BC_CLIENT_ID']
6+
config.client_secret = ENV['BC_CLIENT_SECRET']
7+
config.access_token = ENV['BC_ACCESS_TOKEN']
8+
end
9+
10+
# Get a customer
11+
customer = Bigcommerce::Customer.all(page: 1).first
12+
13+
# Generate token login url
14+
puts customer.login_token

lib/bigcommerce.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module Bigcommerce
1212
Dir.glob(resources, &method(:require))
1313

1414
class << self
15-
attr_reader :api
15+
attr_reader :api, :config
1616

1717
def configure
1818
@config = Bigcommerce::Config.new.tap { |h| yield(h) }

lib/bigcommerce/resources/customers/customer.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
require 'jwt'
2+
require 'securerandom'
3+
14
# Customer
25
# Identity and account details for customers shopping at a Bigcommerce store.
36
# https://developer.bigcommerce.com/api/stores/v2/customers
@@ -26,5 +29,21 @@ class Customer < Resource
2629
def self.count(params = {})
2730
get 'customers/count', params
2831
end
32+
33+
# Generate a token that can be used to log the customer into the storefront.
34+
# This requires your app to have the store_v2_customers_login scope and to
35+
# be installed in the store.
36+
def login_token(config: Bigcommerce.config)
37+
payload = {
38+
'iss' => config.client_id,
39+
'iat' => Time.now.to_i,
40+
'jti' => SecureRandom.uuid,
41+
'operation' => 'customer_login',
42+
'store_hash' => config.store_hash,
43+
'customer_id' => id
44+
}
45+
46+
JWT.encode(payload, config.client_secret, 'HS256')
47+
end
2948
end
3049
end
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,35 @@
11
RSpec.describe Bigcommerce::Customer do
2-
before(:each) { @customer = Bigcommerce::Customer }
3-
42
describe '.count' do
53
it 'should hit the correct path' do
6-
expect(@customer).to receive(:get).with('customers/count', {})
7-
@customer.count
4+
expect(described_class).to receive(:get).with('customers/count', {})
5+
described_class.count
6+
end
7+
end
8+
9+
describe '.login_token' do
10+
let(:client_id) { SecureRandom.hex(6) }
11+
let(:client_secret) { SecureRandom.hex(6) }
12+
let(:store_hash) { SecureRandom.hex(4) }
13+
let(:customer_id) { Random.rand(1000) }
14+
let(:customer) { described_class.new(id: customer_id) }
15+
subject { customer.login_token }
16+
17+
before do
18+
Bigcommerce.configure do |config|
19+
config.store_hash = store_hash
20+
config.client_id = client_id
21+
config.client_secret = client_secret
22+
end
23+
end
24+
25+
it 'should generate a signed token with the right payload' do
26+
payload = JWT.decode(subject, client_secret, true, { :algorithm => 'HS256' })[0]
27+
expect(payload['iss']).to eq(client_id)
28+
expect(payload['store_hash']).to eq(store_hash)
29+
expect(payload['operation']).to eq('customer_login')
30+
expect(payload['customer_id']).to eq(customer_id)
31+
expect(payload['iat']).to be <= Time.now.to_i
32+
expect(payload['jti']).to_not be_empty
833
end
934
end
1035
end

0 commit comments

Comments
 (0)