Stripe connect doesn't giver error but doesn't create accounts - ruby-on-rails

I am currently working on integrating stripe connect to my app but it isn't working. I don't get any errors when I run it and it asks me to create an account and redirects back to the website but when I check my stripe dashboard, it doesn't show any added accounts. Any help would be appreciated! I looked over their documentation and copied that but I got the same results.
Here is some of my code:
class StripeController < ApplicationController
def connect
response = HTTParty.post("https://connect.stripe.com/oauth/token",
query: {
client_secret: ENV["STRIPE_SECRET_KEY"],
code: params[:code],
grant_type: "authorization_code"
}
)
if response.parsed_response.key?("error")
redirect_to welcome_path,
notice: response.parsed_response["error_description"]
else
stripe_user_id = response.stripe_user_id
current_user.stripe_user_id = stripe_user_id
redirect_to mypage_path,
notice: 'User successfully connected with Stripe!'
end
end
end
module UsersHelper
def stripe_button_link
stripe_url = "https://connect.stripe.com/express/oauth/authorize"
redirect_uri = stripe_connect_url
client_id = ENV["STRIPE_CLIENT_ID"]
"#{stripe_url}?response_type=code&redirect_uri=#{redirect_uri}&client_id=#{client_id}&scope=read_write"
end
end
<% if current_user.stripe_user_id %>
<%= link_to "Go to Stripe Dashboard", stripe_dashboard_path(current_user.id) %>
<% else %>
<%= link_to image_tag("ConnectwithStripe.png", width:"120px", height:"40px"), stripe_button_link %>
<% end %>

Before I dive in to your specific code and question I wanted to flag that using OAuth with Express accounts is no longer recommended by Stripe. You should be creating Express accounts using the /v1/accounts API and using Account Links instead.
With that out of the way, I believe the main issue with your code is that you're using HTTParty.post instead of HTTParty.get. When the user is redirected from the OAuth flow back to your website it will be a regular GET request, not a POST.
Once the user is redirected back to your site you need to use the authorization code in the URL to complete the connection process. It's not clear if the code for this is missing or was omitted from your question, but you need to do something like this somewhere:
response = Stripe::OAuth.token({
grant_type: 'authorization_code',
code: 'AUTHORIZAION_CODE_FROM_URL_HERE',
})
# Store the response.stripe_user_id (the Stripe account ID) in your database for use in the Stripe-Account header when making Connect requests
stripe_account_id = response.stripe_user_id

Related

How to access flickr user id from username search API call

I am working on a small app to access the flickr api and serve up photos. I am using the flickr gem for auth. It is working for recent photos, which are displayed if nothing is entered in the form yet. It is working for search by tags. It was working by user_id, but I am trying to change it to accept username, and then use the flickr.people.findByUsername method to get the user id and then use that to pull up the photos. It's easy to find peoples usernames on the flickr website, but hard to find ID's so I think this will be more user friendly. Here's the current version of the app before I branched it to attempt this. https://flickr-photo-feed.herokuapp.com/ It's a very basic app with no model and no database. There is only the index controller action and a very basic form partial and another partial to render the returned photos.
I changed the form to accept username
<div class="form">
<%= form_with url: :root, method: :get do |form| %>
<%= form.text_field :username, placeholder: "Username", class: "form-field" %>
<%= form.text_field :tags, placeholder: "tags", class: "form-field" %>
<%= form.submit 'submit', class: "submit-btn" %>
<% end %>
</div>
Here is the controller:
class StaticPagesController < ApplicationController
require "flickr"
def index
#flickr = Flickr.new
if params[:username].present?
user_id = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id
elsif params[:tags].present?
#photos = #flickr.photos.search tags: params[:tags], safesearch: 1
else
#photos = #flickr.photos.getRecent
end
end
end
If I enter a username, I get this error:
undefined method `delete' for {"id"=>"132822455#N05","nsid"=>"132822455#N05",
"username"=>"images#twiston"}:Flickr::Response Extracted source
(around line #8): 6 7 8 9 10 11
if params[:username].present?
user_id = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id
elsif params[:tags].present?
#photos = #flickr.photos.search tags: params[:tags], safesearch: 1
else
with this error in the rails server:
oauth_args = args.delete(:oauth) || {}
As you can see, I'm getting a response with the nsid in it. I don't quite understand the no method error for delete, but I gather that it is coming from the flickr gem. So, I figure that I need pull the nsid out of the hash and pass it to my api call. So, I change one line to be:
#photos = #flickr.people.getPhotos user_id["nsid"]
which generates this error:
no implicit conversion of Symbol into String
So, I try this:
#photos = #flickr.people.getPhotos user_id[:nsid]
which gives me this error:
undefined method `delete' for nil:NilClass
I even tried this:
#photos = #flickr.people.getPhotos user_id.nsid
which gets me this error:
no implicit conversion of Symbol into String
I have tried a few other things as well, but the result is always one of those error messages. can anyone point out where I'm going wrong? Thank you.
Edit: I've been able to verify that I can puts the user_id["nsid"] and the correct nsid is output to the rails server. However, I still get the "no implicit conversion of symbol to string" error. So, I tried saving it to a variable and explicitly calling .to_str on it before passing it to the #flickr.people.getPhotos method. I have verified with p (not puts) that it does get output as a string. The ""show up around it. However, that particular error persists.
Edit to add the initializers/flickr.rb file:
require "dotenv/load"
require "flickr"
flickr_api_key = ENV["FLICKR_API_KEY"]
flickr_shared_secret = ENV["FLICKR_SHARED_SECRET"]
flickr = Flickr.new flickr_api_key, flickr_shared_secret
# This is the URL Flickr will redirect your users to once they agree to access
#callback_url = "http://localhost:3000/auth_controller/callback"
# Users should hit this method to get the link which sends them to flickr
def auth
flickr = Flickr.new API_KEY, SHARED_SECRET
token = flickr.get_request_token(oauth_callback: URI.escape(#callback_url))
# You'll need to store the token somewhere for when the user is returned to the callback method
# I stick mine in memcache with their session key as the cache key
#auth_url = flickr.get_authorize_url(token["oauth_token"], perms: "delete")
# Stick #auth_url in your template for users to click
end
# Your users browser will be redirected here from Flickr (see #callback_url above)
def callback
flickr = Flickr.new
request_token = # Retrieve from cache or session etc - see above
oauth_token = params[:oauth_token]
oauth_verifier = params[:oauth_verifier]
raw_token =
flickr.get_access_token(
request_token["oauth_token"],
request_token["oauth_token_secret"],
oauth_verifier
)
# raw_token is a hash like this {"user_nsid"=>"92023420%40N00", "oauth_token_secret"=>"XXXXXX", "username"=>"boncey", "fullname"=>"Darren%20Greaves", "oauth_token"=>"XXXXXX"}
# Use URI.unescape on the nsid and name parameters
oauth_token = raw_token["oauth_token"]
oauth_token_secret = raw_token["oauth_token_secret"]
# Store the oauth_token and oauth_token_secret in session or database
# and attach to a Flickr instance before calling any methods requiring authentication
# Attach the tokens to your flickr instance - you can now make authenticated calls with the flickr object
flickr.access_token = oauth_token
flickr.access_secret = oauth_token_secret
end
The documentation is not great, but it looks like it should be:
flickr = Flickr.new "api key", "api secret"
#user = flickr.people.findByUsername username: 'images#twiston'
#=> {"id"=>"132822455#N05", "nsid"=>"132822455#N05", "username"=>"images#twiston"}
Which give you:
#user['nsid']
#=> "132822455#N05"
#user['id']
#=> "132822455#N05"
So your code should be something like:
#user = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id: #user['id']
The findByUsername method returns that hash and you were treating it as if it returns just the :id.
The docs say:
Alternatively, if the API key and Shared Secret are not provided, Flickr will attempt to read them from environment variables:
ENV['FLICKR_API_KEY']
ENV['FLICKR_SHARED_SECRET']
You could use the console to do a manual authentication with the key and secret per my example to make sure it's working right.
response = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id: response["nsid"]
Beartech was correct. This worked right away.

New Stripe SCA checkout flow in Rails

I'm struggling with switching my Rails app to the new Stripe checkout flow to accommodate the new SCA regulation.
I want to implement the simple dynamic product routine found in this link: https://stripe.com/docs/payments/checkout/migration#api-products-after
I can't figure out where to put the different pieces of code. What should go in:
- controller -> in which methods
- views -> the event show view for example. The form/button the user will click
- javascript -> how to pass the right session id
- controller again -> implementing the success and error use cases
The Stripe tech support just sent me to the documentation link above so I would really appreciate some help here.
The Rails workflow for the new Stripe Checkout is:
Create a Stripe Checkout Session and retrieve the session.id (.rb)
Pass the session.id to a js initializer to redirect to Stripe Checkout
STRIPE CHECKOUT SESSION
This is a sample client/server Stripe Checkout implementation that I'm using for a Subscription service. Your steps would essentially be the same except you would be referencing a Stripe Product rather than a Plan:
subscriptions_controller.rb
STRIPE_API_KEY = Rails.application.credential.stripe[:secret_key]
skip_before_action :user_logged_in?, only: :stripe_webhook
protect_from_forgery except: :stripe_webhook
def stripe_webhook
stripe_response = StripeWebhooks.subscription_events(request)
end
def index
end
def new
session = StripeSession.new_session(STRIPE_API_KEY, current_user.email, params[:plan])
#stripe_session = session
end
In my case, my index.html.erb template has a link to "Get more info..." about a particular subscription. That link goes to the controller's :new action, passing the relevant Stripe Plan (or Product) info as params. In your case, you might pass whatever Product params necessary for your Stripe Checkout session:
subscriptions/index.html.erb
<%= link_to 'Get more info...', new_subscription_path(plan: 'plan_xxx' %>
The :new controller action will return your Stripe CHECKOUT_SESSION_ID for use in your template. (Also, note that this controller is bypassing logged_in? and forgery protection to allow for the Stripe Webhook POST response to your Checkout Session. You'll need to address your particular authorization scheme here)
Now, you need to call the Stripe API. I'm doing this in a Stripe service like so:
app/services/stripe_session.rb
class StripeSession
require 'stripe' ### make sure gem 'stripe' is in your Gemfile ###
def self.new_session(key, user_email, plan)
new(key, customer_email: user_email, plan: plan).new_checkout_session
end
def initialize(key, options={})
#key = key
#customer_email = options[:customer_email]
#plan = options[:plan]
end
def new_checkout_session
Stripe.api_key = key
session = Stripe::Checkout::Session.create(
customer_email: customer_email,
payment_method_types: ['card'],
subscription_data: {
items: [{
plan: plan,
}],
},
success_url: 'https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://yourapp.com/cancel'
)
end
private
attr_reader :key, :customer_email, :plan
end
If your call to Stripe was successful the session object in your controller :new action will now contain your session data:
def new
session = StripeSession.new_session(STRIPE_API_KEY, current_user.email, params[:plan])
#stripe_session = session
end
JS SCRIPT LOADING
You'll be using the session.id in your link to redirect to the Stripe Checkout page:
subscriptions/new.html.erb
<%= content_for :header do %>
<script src="https://js.stripe.com/v3/" data-turbolinks-eval="false"></script>
<% end %>
<div data-stripe="<%= #stripe_session.id %>">
<%= link_to 'Subscribe', '', class: 'subscribe-btn', remote: true %>
</div>
<script>
const subscribeBtn = document.querySelector('.subscribe-btn')
subscribeBtn.addEventListener('click', e => {
e.preventDefault()
const CHECKOUT_SESSION_ID = subscribeBtn.parentElement.dataset.stripe
stripe.redirectToCheckout({
sessionId: CHECKOUT_SESSION_ID
}).then((result) => {
// handle any result data you might need
console.log(result.error.message)
})
}
</script>
The above template is doing several important things:
Load the stripe v3 js script (it's up to you how/where you load this script. If using content_for then your layout.html file would have a corresponding block:
<% if content_for? :add_to_head %> <%= yield :add_to_head %> <% end %>
Pass the #stripe_session.id from the controller :new action to the data-stripe-id attribute of your <div> element.
Add the EventListener for the subscribe-btn to redirect to Stripe Checkout, passing in the #stripe_session.id
ALTERNATE APPROACH FOR JS SCRIPTS
There are other ways to load the js scripts. Personally, I love using Stimulus for this sort of thing. For example, rather than loading js with content_for and using <script> tags I have a subscription_controller.js Stimulus Controller doing the work:
subscriptions/new.html.erb (now becomes)
<div data-controller="subscription" data-session="<%= #stripe_session.id %>">
<%= link_to 'Subscribe', '', class: 'btn', remote: true,
data: {action: 'subscription#redirectToCheckout', target: 'subscription.sessionID'}
%>
</div>
---
(The Stimulus controller)
app/javascript/controllers/subscription_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
static targets = [ 'sessionID' ]
get sessionID() {
return this.sessionIDTarget.parentElement.dataset.session
}
initialize() {
const script = document.createElement('script')
script.src = "https://js.stripe.com/v3/"
document.head.appendChild(script)
}
redirectToCheckout(e) {
e.preventDefault()
// grab your key securely in whichever way works for you
const stripe = Stripe('pk_test_xxx')
const CHECKOUT_SESSION_ID = this.sessionID
stripe.redirectToCheckout({
sessionId: CHECKOUT_SESSION_ID
}).then((result) => {
console.log(result.error.message)
})
}
}
You would need to add/initialize Stimulus to your Rails app for the above to work...
STRIPE WEBHOOKS
Stripe will POST to your webhook endpoints (if you configure them to). If listening for them, you configure some routes (see below) to handle them. You can also do this in a service of your choosing. For example, create another file in your app/services folder:
app/services/stripe_webhooks.rb
class StripeWebhooks
require 'stripe'
STRIPE_API_KEY = Rails.application.credentials.stripe[:secret_key]
def self.subscription_events(request)
new(request).subscription_lifecycle_events
end
def initialize(request)
#webhook_request = request
end
def subscription_lifecycle_events
authorize_webhook
case event.type
when 'customer.created'
handle_customer_created
when 'checkout.session.completed'
handle_checkout_session_completed
when # etc.
end
end
private
attr_reader :webhook_request, :event
def handle_customer_created(event)
## your work here
end
def handle_checkout_session_completed(event)
## your work here
end
def authorize_webhook
Stripe.api_key = STRIPE_API_KEY
endpoint_secret = Rails.application.credentials.stripe[:webhooks][:subscription]
payload = webhook_request.body.read
sig_header = webhook_request.env['HTTP_STRIPE_SIGNATURE']
#event = nil
begin
#event = Stripe::Webhook.construct_event(
payload, sig_header, endpoint_secret
)
rescue JSON::ParserError => e
puts e.message
rescue Stripe::SignatureVerificationError => e
puts e.message
end
end
end
This file will receive and authorize the incoming Stripe webhook that you configured in your Stripe Dashboard. If successful, event attribute will contain the JSON response of whichever webhook you're ingesting at the moment.
That allows you to call various methods based on the event.type which will be the name of the webhook. event.data.object will get you into specific response data.
RAILS ROUTES
None of the above will work without the proper routes!
routes.rb
get 'success', to: 'subscriptions#success'
get 'cancel', to: 'subscriptions#cancel'
resources :subscriptions
post '/stripe-webhooks', to: 'subscriptions#stripe_webhook'
I had to place the get 'success' & 'cancel' routes above the subscription resources for them to resolve properly.
And, finally, add the success and cancel callbacks to your controller and do whatever you need with them. For example:
subscriptions_controller.rb
...
def success
### the Stripe {CHECKOUT_SESSION_ID} will be available in params[:session_id]
if params[:session_id]
flash.now[:success] = "Thanks for your Subscribing/Purchasing/Whatever..."
else
flash[:error] = "Session expired error...your implementation will vary"
redirect_to subscriptions_path
end
end
def cancel
redirect_to subscriptions_path
end
...
Note: you'll need a corresponding success.html.erb file. The cancel action can redirect or create an html.erb file for that too if you'd like.
So, it was kind of a bear to get it all setup. However, with the plumbing out of the way there are lots of cool possibilities to handle all sorts of lifecycle events/webhooks. Currently, I'm listening for about 15 of them to keep my subscription system running smoothly.
Good luck!
I'm not using ruby but in the case to pass the session ID when Success checkout is Done when creating the session just add "?session_id={CHECKOUT_SESSION_ID}" after the * _url,
Don't know if this is your case but glad to help
mode : "subscription",
customer : customerid,
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel?session_id={CHECKOUT_SESSION_ID}',
also, I suggest watching this https://youtube.com/watch?v=8TNQL9x6Ntg

Not receiving money in Stripe test transactions (Rails)

So I created subscriptions in my Rails app with test API keys from Stripe.
The charges I'm creating with dummy cards are going through successfully on my side, but when I'm in Stripe dashboard, the test balance remains the same, as well customer details are not added. I'm not sure what I did wrong.. Do you know why I can't and how can I add those test customer data to Stripe? In the logs, I'm getting 200 OK response, but I'm worried that something isn't going to function in live mode since test balance isn't being updated.
class SubscribersController < ApplicationController
before_filter :authenticate_user!
def new
end
def update
token = params[:stripeToken]
customer = Stripe::Customer.create(
card: token,
plan: 1020,
email: current_user.email
)
current_user.subscribed = true
current_user.stripeid = customer.id
current_user.save
redirect_to profiles_user_path
end
end
and _form.html.erb
<%= form_tag profiles_user_path, method: :get do %>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="8999"></script><span> $89 per month </span>
<% end %>
Make sure you're using your Stripe test API keys, and not your live keys. These can be found in the "API keys" section of your account settings from the Stripe dashboard:
So the API keys you're using should include _test_.
For testing, you should also consider using StripeMock, which runs a virtual Stripe server to emulate Stripe: https://github.com/rebelidealist/stripe-ruby-mock.
EDIT
If you're still getting errors, then check your stripe logs and provide a redacted copy here:
It took my almost a year to find this out.
I was using tipsi-stripe on my react-native app, only.
I was not aware I needed to send the token to my own backend. And my backend needed to communicate with stripe REST API in order to use that token and create a payment out of that.
https://stripe.com/docs/payments/accept-a-payment-charges

How to Handle OAuth Response with Octokit Ruby vs Restclient

Hi I'm new to Ruby/Rails and I had a question about handling an OAuth response with the Ruby version of GitHub's Octokit. After reading the documentation I'm a little confused about how to follow best practices with the wrapper vs with RestClient. When I authorize my app the response returns a "code" which I'm supposed to exchange for an access token.
In the GitHub API documentation it shows a Sinatra example of this with Restclient, which is currently in my create action of the sessions controller. However, it says you should approach it differently when building an app and that you should use the Octokit library, but I can't find any documentation on exactly how to exchange the code for an access token with Octokit.
My goal is to be able to crete a new member for the app via a user's GitHub account, save that info, & then sign them in with that account, rather then ever creating a username/password. I've pasted my new.html.erb code below to show the request that I am making as well. Really appreciate any help, thank you!
Sessions Controller
class SessionsController < ApplicationController
def new
#client_id = Octokit.client_id
end
def create
# CHANGE THIS TO USE OCTOKIT INSTEAD
session_code = request.env['rack.request.query_hash']['code']
result = RestClient.post('https://github.com/login/oauth/access_token',
{:client_id => Octokit.client_id,
:client_secret => Octokit.client_secret,
:code => session_code},
:accept => :json)
access_token = JSON.parse(result)['access_token']
end
end
OAuth Request
<p>
Sign In with GitHub
</p>
<p>
Click here to begin!</a>
</p>
As it doesn't explicitly state this in the README. What I recommend is always going through the source code to get a better understanding of how a gem works. Often you will find that the gem's creator(s) have written great code that is self-explanatory, and sometimes even commented to provide more info as in the situation below. Here is the method you're looking for, good luck on your journey to learn to Ruby/Rails and welcome! Let me know if you have any more questions and run into any more issues getting this to work.
# Retrieve the access_token.
#
# #param code [String] Authorization code generated by GitHub.
# #param app_id [String] Client Id we received when our application was registered with GitHub.
# #param app_secret [String] Client Secret we received when our application was registered with GitHub.
# #return [Sawyer::Resource] Hash holding the access token.
# #see http://developer.github.com/v3/oauth/#web-application-flow
# #example
# Octokit.exchange_code_for_token('aaaa', 'xxxx', 'yyyy', {:accept => 'application/json'})
def exchange_code_for_token(code, app_id = client_id, app_secret = client_secret, options = {})
options.merge!({
:code => code,
:client_id => app_id,
:client_secret => app_secret,
:headers => {
:content_type => 'application/json',
:accept => 'application/json'
}
})
post "#{web_endpoint}login/oauth/access_token", options
end

parsing # in rails uris

i am getting the following url information and need to parse it within rails. i already checked request and params but it is not there.
the "#" character seems to f*ck up things.
here's the url:
http://foo.bar.me/whoo#access_token=131268096888809%7C2.5BRBl_qt4xJ08n88ycbpZg__.3600.1276880400-100001151606930%7C0kJ1K-qoGBbDoGbLx6s4z5UEaxM.
thanks for any pointers.
You won't be able to access the part after the '#' character as the browser doesn't send it to the server. You can use it on the client side with javascript though.
It seems that you're trying to use the javascript based authentication which is not what you really want.
I didn't have any problems using this oauth2 library. Then you only need to check for params[:code] within your callback action.
UPDATE:
This is a simplified version of the code I used in my experiments with the new facebook graph API:
# Accessible as facebook_url:
# routes.rb: map.facebook '/facebook', :controller => 'facebook', :action => 'index'
def index
oauth2 = OAuth2::Client.new(FB_API_KEY, FB_API_SECRET, :site => 'https://graph.facebook.com')
if current_user.facebook_token
# The user is already authenticated
fb = OAuth2::AccessToken.new(oauth2, current_user.facebook_sid)
result = JSON.parse(fb.get('/me'))
elsif params[:code]
# Here we get the access token from facebook
fb = oauth2.web_server.get_access_token(params[:code], :redirect_uri => facebook_url)
result = JSON.parse(fb.get('/me'))
current_user.facebook_id = result["id"]
current_user.facebook_token = fb.token.to_s
current_user.save
else
# The user is visiting this page for the first time. We redirect him to facebook
redirect_to oauth2.web_server.authorize_url(:redirect_uri => facebook_url, :scope => 'read_stream,publish_stream,offline_access')
end
end
You don't really need anything else for it to work.

Resources