question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can token be used to link debit card to Stripe-Connect account?

See original GitHub issue

Hey,

First of all thanks for creating this package!

My question is: I am currently implementing Stripe Connect in my RNapp. To link a users debit card to a stripe account (so that the user can receive payments from other users), I need to pass a token that is created with Stripe.js.

I thought the token returned by stripe.createTokenWithCard() would return said token that I can then send to the backend to make the actual connection. However, I get an error saying that the token I am providing is not from Stripe.js.

Is the token returned by stripe.createTokenWithCard() some other (maybe own created) token?

Thanks in advance!

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:23 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
Andrfascommented, Sep 12, 2018

@wmonecke @larryranches I have the same question

2reactions
wmoneckecommented, Sep 26, 2019

Here is some code, it is a bit messy but I had to do it in a rush. If you need any help or clarification I will gladly help you!

FRONT END - the stripe class referenced here is coming from tipsi-stripe and NOT stripe.js.

// first you create the customer account

export const createStripeCustomerAccount = (email, uid, callback) => {
  firebase.auth().currentUser.getIdToken(true).then(idToken => {
    // Send firebase idToken to your backend via HTTPS
    axios({
      method: 'post',
      url: 'https://us-central1-lisdo-6bf0d.cloudfunctions.net/createStripeCustomerAccount',
      headers: {
        'Authorization': 'Bearer ' + idToken
      },
      data: {
        email: email,
        user_uid: uid,
        user_type: 'serviceUsers'
      }
    })
    .then(res  => {
      if (res.status === 200) {
        // grab stripe account id and send it to the callback to be saved in firebase and/or your local storage
        let stripeID = res.data.stripeID;

        return callback(stripeID);
      }
    })
    .catch(err => console.log('error while doing get req createStripeAccount:', err));

  }).catch(error => {
    // Handle error
    console.log('Error retrieving IdToken!', err);
  });
}

// then AFTER creating the user account you create a token of a card using tipsi-stripe

createTokenFromCard() {
    const { number, cvc, expiry, name, type } = this.state.cardForm.values;
    const expiryMonth         = expiry.substr(0, expiry.indexOf('/'))*1;
    const expiryYear          = expiry.substr(expiry.indexOf('/')+1)*1;
    const sanitizedCardNumber = number.replace(/\s/g,'');

    const params = {
      number: sanitizedCardNumber,
      expMonth: expiryMonth,
      expYear: expiryYear,
      cvc: cvc,
      name: name,
      object: 'card',
      currency: 'eur'
    };

    return this.setState({ makingCardRequest: true }, () => {
      return stripe.createTokenWithCard(params)
      .then(token   => this.props.addCardToStripeAccount(token.tokenId, this.props.user.stripeID))
      .catch(error  => console.log('error creating token', error));
    });
  }

  // after getting the necessary data of the card and having the TOKEN using tipsi-stripe I called the following action to actually add a card to an existing account. The stripeID is the one we got by calling createStripeCustomerAccount()

export const addCardToStripeAccount = (tokenId, stripeID) => {
  return (dispatch) => {

    const { currentUser } = firebase.auth();

    firebase.auth().currentUser.getIdToken(true).then(idToken => {

      axios({
        method: 'post',
        url: 'https://us-central1-lisdo-6bf0d.cloudfunctions.net/addCardToStripeAccount',
        headers: {
          'Authorization': 'Bearer ' + idToken
        },
        data: {
          tokenId: tokenId,
          stripeID: stripeID,
        }
      })
      .then(res  => {
        if (res.status === 200) {
          return dispatch({ type: ADD_CARD_TO_ACCOUNT_SUCCESS });
        }
      })
      .catch(err => console.log('error while doing get req addCardToStripeAccount:', err));

    })
    .catch(error => console.log('Error retrieving users ID token', error));
  }
}

BACK END - the stripe class referenced here is coming from stripe.js and NOT tipsi-stripe. That is the whole point of having the backend in the first place.

exports.addBankAccountToStripeAccount = functions.https.onRequest((req, res) => {
  verifyUser(req, res, decodedIdToken => {

    const user_type = req.body.user_type;
    const tokenId   = req.body.tokenId;
    const user_uid  = decodedIdToken.uid;
    const stripeID  = req.body.stripeID;
    const userData  = req.body.userData;

    const updateStripeObject =
      userData.accountHolderType === 'individual'
      ?
      {
        legal_entity: {
          address: {
            city: userData.personal_city,
            postal_code: userData.personal_postal_code,
            line1: userData.personal_line1,
          },
          dob: {
            day: userData.dob_day,
            month: userData.dob_month,
            year: userData.dob_year,
          },
          first_name: userData.first_name,
          last_name: userData.last_name,
          type: userData.accountHolderType,
        },
        tos_acceptance: {
          date: Math.floor(Date.now() / 1000),
          ip: req.connection.remoteAddress
        }
      }
      :
      {
        legal_entity: {
          additional_owners: [],
          address: {
            city: userData.business_city,
            postal_code: userData.business_postal_code,
            line1: userData.business_line1,
          },
          personal_address: {
            city: userData.personal_city,
            postal_code: userData.personal_postal_code,
            line1: userData.personal_line1,
          },
          dob: {
            day: userData.dob_day,
            month: userData.dob_month,
            year: userData.dob_year,
          },
          first_name: userData.first_name,
          last_name: userData.last_name,
          type: userData.accountHolderType,
          business_name: userData.business_name,
          business_tax_id: userData.business_tax_id,
        },
        tos_acceptance: {
          date: Math.floor(Date.now() / 1000),
          ip: req.connection.remoteAddress
        }
      }

    let promises = [];

    promises.push(stripe.accounts.createExternalAccount(stripeID, { external_account: tokenId }));
    promises.push(stripe.accounts.update(stripeID, updateStripeObject));

    Promise.all(promises)
    .then(response => {

      const bankAccount = response[0];

      let bankName = bankAccount.bank_name;
      let last4    = bankAccount.last4;
      let type     = bankAccount.object;
      let status   = bankAccount.status;

      let updates = {};
      updates[`/allUsers/${user_type}/${user_uid}/payoutDetails/type`]     = type;
      updates[`/allUsers/${user_type}/${user_uid}/payoutDetails/last4`]    = last4;
      updates[`/allUsers/${user_type}/${user_uid}/payoutDetails/status`]   = status;
      updates[`/allUsers/${user_type}/${user_uid}/payoutDetails/bankName`] = bankName;

      return admin.database().ref().update(updates)
      .then(() => res.status(200).send({ status: 'success' }))
      .catch(err => {
        console.log("error:", err)
        res.status(400).send({
          error: err,
          description: 'Error while updating firebase from cloud function in *addBankAccountToStripeAccount*'
        })
      });

    })
    .catch(err => {
      console.log('error', err)
      res.status(400).send({
        error: err,
        description: 'Error, not all Promises resolved in *addBankAccountToStripeAccount*'
      })
    });
  });
});

// The actual method to add the card your users connect account.

exports.addCardToStripeAccount = functions.https.onRequest((req, res) => {
  verifyUser(req, res, (decodedIdToken) => {

    const user_uid  = decodedIdToken.uid;
    const tokenId   = req.body.tokenId;
    const stripeID  = req.body.stripeID;

    return stripe.customers.update(stripeID, { source: tokenId })
    .then(customer => {

      const { last4, brand, id } = customer.sources.data[0];

      let updates = {};
      updates[`/allUsers/serviceUsers/${user_uid}/paymentDetails/last4`]  = last4;
      updates[`/allUsers/serviceUsers/${user_uid}/paymentDetails/cardID`] = id;
      updates[`/allUsers/serviceUsers/${user_uid}/paymentDetails/brand`]  = brand;

      return admin.database().ref().update(updates)
      .then(() => res.status(200).send({ status: 'success' }))
      .catch(err => res.status(400).send({
        error: err,
        description: 'Error while updating firebase from cloud function in *addCardToStripeAccount*'
      }));
    })
    .catch(error => console.log('Error while adding card to serviceUser', error));
  });
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Using tokens to securely transmit account data - Stripe
Connect platforms can use Stripe.js to securely collect account details from their ... Tokens cannot be used for any other account information, including:....
Read more >
Auth - Stripe | Plaid Docs
Plaid will automatically create and return a Stripe bank account token for this account, which can then be used to move money via...
Read more >
Apple Pay security and privacy overview
When you add a credit, debit, prepaid, or transit card (where ... The Device Account Number can't be decrypted by Apple but is...
Read more >
Stripe Payment: Save token and customer and make payment ...
In Stripe, in order to save a card (or bank account) to charge later, you have to create a customer, then add payment...
Read more >
Integrating Plaid Link with Stripe | by Connor Parsons | Medium
Plaid's link API is a super slick tool for authenticating bank account ... token, which can be used to query Plaid for other...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found