Rentabiliser un webservice avec stripe et firebase

Un rapide exemple (sale et en javascript pure !!!), pour utiliser stripe et firebase pour rentabiliser un webservice (ou une application : web, mobile, …).

  • Firebase est là pour stocker les données (paiements, utilisation des services).
  • Stripe est là pour encaisser les paiements.

Please accept YouTube cookies to play this video. By accepting you will be accessing content from YouTube, a service provided by an external third party.

YouTube privacy policy

If you accept this notice, your choice will be saved and the page will refresh.

Les imports pour stripe, firebase et firebaseui

        <script src="https://www.gstatic.com/firebasejs/6.2.4/firebase-app.js"></script>
        <script src="https://www.gstatic.com/firebasejs/6.2.4/firebase-auth.js"></script>
        <script src="https://www.gstatic.com/firebasejs/6.2.4/firebase-firestore.js"></script>
        <script src="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.js"></script>

        <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.css" />

L’authentification (avec Firebase)

L’idée est d’utiliser le module et la gestion des authentifications de firebase … niveau script, il nous suffit d’importer les éléments suivant :

On n’oublie pas d’activer l’authentification sur firebase !!!

Ici j’utilise uniquement Google, vous pouvez utiliser le classique ‘adresse mail mot de passe’ …

Configuration de firebase et firebase ui

var firebaseConfig = {
    apiKey: "...",
    authDomain: "....-1.firebaseapp.com",
    databaseURL: "https://....-1.firebaseio.com",
    projectId: "....-1",
    storageBucket: "",
    messagingSenderId: "....",
    appId: "...."
};

//Configuration de notre ui d'aauthentification (une magnifique popup demandant le login/mot de passe).
var uiConfig = {
    callbacks: {
        signInSuccessWithAuthResult: function(authResult, redirectUrl) {return false;},
        signInFailure: function(error) {return handleUIError(error);},
    },
    credentialHelper: firebaseui.auth.CredentialHelper.NONE,
    signInOptions: [firebase.auth.EmailAuthProvider.PROVIDER_ID],
    signInFlow: 'popup'
};

//initialisation de l'app
firebase.initializeApp(firebaseConfig);
var ui = new firebaseui.auth.AuthUI(firebase.auth());

Le listener d’authentification

C’est ici que l’on sera si l’utilisateur s’est authentifié ou non, l’action e login ou de logout seront donc des actions asynchrones !!!

var userid = '';
firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        var displayName = user.displayName;
        document.getElementById('login').innerHTML=user.email+' <a href="javascript:logout()">(logout)</a>';
        firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
            userid=idToken;
        }).catch(function(error) {
            console.log(error);
        });
    }else{
        document.getElementById('login').innerHTML='<a href="javascript:login()">Login</a>';
    }
});

Login et Logout

function login(){
//on ne fait qu'afficher la popup d'authentification !!
    ui.start('#firebaseui-auth-container', uiConfig);
}
function logout(){
    firebase.auth().signOut().then(function() {
      console.log('Signed Out');
        userid='';
    }, function(error) {
      console.error('Sign Out Error', error);
    });
}

Et c’est tout pour l’uthentification !!!

Connexion à la DB de Firestore

une fois l’application firebase initialisé (via initializeApp plus haut),il suffit de faire :

//db sera notre accès à la base de données :
var db = firebase.firestore();

//Ici on veut accéder à /user/userid/date/unedate
db.collection("users").doc(userid).collection('date').doc(date).onSnapshot(function(doc) {
                data=doc.data(); document.getElementById("nb_token").innerHTML= (data&&data.nb_upload?data.nb_upload:0);
            });

Ici à chaque fois que la donnée dans la base de données changera, notre div sera mise à jour avec la valeur de mon objet.

Stripe pour le paiement

On récupère nos clés de développement sur le site de stripe

Ensuite, on a juste à utiliser les différents éléments fournit par la documentation.

Les éléments importants (dans l’ordre) sont :

  • stripe=Stripe() <- créer l’instance de l’objet
  • card = stripe.elements() <- créer un composant
  • card.mount <- ajoute l’élément de le dom (devient visible)
  • stripe.createToken(card) <- créer un token de paiment
  • Envoi du token à votre serveur pour paiement.

Simple exemple d’enchaînement côté client avec appel du webservice (postToken) :
paywall affiche le composant, et créer le token
stripeTokenHandler ajoute un champ pour le token et le post via postToken
postToken l’envoi au serveur

function paywall(){
    document.getElementById('paywall').style.display='block';
    document.getElementById('error').style.display='none';
    var stripe = Stripe('pk_test_cle_de_test');
    var elements = stripe.elements();
    var style = {
      base: {
        // Add your base input styles here. For example:
        fontSize: '16px',
        color: "#32325d",
      }
    };
    // Create an instance of the card Element.
    var card = elements.create('card', {style: style});
    // Add an instance of the card Element into the `card-element` <div>.
    card.mount('#card-element');
    card.addEventListener('change', function(event) {
      var displayError = document.getElementById('card-errors');
      if (event.error) {
        displayError.textContent = event.error.message;
      } else {
        displayError.textContent = '';
      }
    });
    var form = document.getElementById('payment-form');
    form.addEventListener('submit', function(event) {
      event.preventDefault();
      stripe.createToken(card).then(function(result) {
        if (result.error) {
          // Inform the customer that there was an error.
          var errorElement = document.getElementById('card-errors');
          errorElement.textContent = result.error.message;
        } else {
          // Send the token to your server.
          stripeTokenHandler(result.token);
        }
      });
    });
}
function stripeTokenHandler(token) {
    var form = document.getElementById('payment-form');
    var hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', 'stripeToken');
    hiddenInput.setAttribute('value', token.id);
    form.appendChild(hiddenInput);
    postToken(token.id);
}
function postToken(token){
    var http = new XMLHttpRequest();
    var url = '/api/pay';
    var params = 'stripeToken='+token;
    http.open('POST', url, true);
    http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    http.onreadystatechange = function() {
        if(http.readyState == 4 && http.status == 200) {
            document.getElementById('paywall').style.display='none';
            document.getElementById('msg_ok').style.display='block';
        }else if(http.readyState == 4 && http.status == 403){
            document.getElementById('paywall').style.display='none';
        }
    }
    http.send(params);
}

Côté serveur, on utilise ici la librairie en python …

from flask import Flask, request, jsonify, render_template,send_file
from flask_cors import CORS
import stripe

stripe.api_key = 'rk_test_cle_prive'

app = Flask(__name__,static_url_path='', static_folder='web',template_folder='web/templates')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
CORS(app)

@app.route('/api/pay', methods=['POST'])
def postpay():
    if request.method == 'POST':
        data = request.form
        charge = stripe.Charge.create(
            amount=500,
            currency='eur',
            description='5 Token',
            source=data['stripeToken'],
            capture=True
        )
        db.collection(u'payments').document(charge['id']).set(charge)
        if charge['status']=="succeeded":
            data = db.collection(u'unauth').document(request.remote_addr+'_'+datetime.now().strftime('%Y%m%d')).set({'nb_upload':0})
            return json.dumps(charge),200
        else:
            return json.dumps(charge),403            
    return '',200

Et c’est tout 🙂