├── .gitignore ├── README.md ├── config └── template.js ├── lib └── server.js ├── package.json ├── public └── global.css ├── server.js └── views ├── connected.pug ├── index.pug └── partials ├── footer.pug ├── head.pug └── nav.pug /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | config/index.js 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A simple Stripe Connect Node demo app 2 | 3 | This is a simple Stripe Connect application written in Node.js with Express. At this point it doesn't do a whole lot, and the intention is primarily to provide a general example to help you get up and running with [Stripe Connect](https://stripe.com/docs/connect). It ~~was totally stolen from~~ is heavily inspired by [A simple PHP Stripe Connect example using OAuth 2]( https://github.com/adamjstevenson/oauth-stripe-connect-php). 4 | 5 | 6 | 7 | 8 | ## Some important things you should know right off the bat 9 | 10 | * This isn't, by any means, ready for production. 11 | * You should read over [Stripe's Connect documentation](https://stripe.com/docs/connect/standalone-accounts) as a first step. 12 | * This example uses [Express](https://expressjs.com/) and [Pug](https://pugjs.org/) to try to keep the actual logic as clear as possible. In theory I could've chosen any framework, but I'm most familiar with Express, so that's what you got. 13 | * This application uses an OAuth 2.0 client library provided by the [Mulesoft](https://github.com/mulesoft/js-client-oauth2). Though [it's possible](https://stripe.com/docs/connect/standalone-accounts#sample-code) to build the OAuth flow out yourself, it's recommended that you use an OAuth library like this one. 14 | * Since the goal here is just to show the connection process, this application doesn't make use of any database. IRL, you'll want to save at least the account ID to your database when your user connects so you can [do things on their behalf](https://stripe.com/docs/connect/authentication#authentication-via-the-stripe-account-header) later. 15 | * This integration uses [standalone accounts](https://stripe.com/docs/connect/standalone-accounts), so you can either create a new test account using [some test data](https://stripe.com/docs/testing), or connect an existing account. 16 | 17 | ## Getting started 18 | 19 | Clone this repository: 20 | 21 | ``` 22 | git clone https://github.com/floatingLomas/stripe-connect-node.git 23 | ``` 24 | 25 | Log in to your Stripe account (or create one) and register your application as a platform. Set a redirect URI in Stripe that points to https://localhost:3000/connected (or whatever you want to set below). 26 | 27 | Copy `config/template.js` to `config/index.js` and add your test secret key, development client ID, redirect URL and the port you want to listen on there. 28 | 29 | Run `npm install` from the project's root directory to install dependencies, then `npm start` to get rolling. 30 | -------------------------------------------------------------------------------- /config/template.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Save this file as `index.js` in this folder with your account's IDs. 4 | // `index.js` is .gitignored so it won't accidentally end up somewhere 5 | // it shouldn't. 6 | 7 | module.exports = exports = { 8 | clientId: 'ca_YOUR_CLIENT_ID', // Your client ID: https://dashboard.stripe.com/account/applications/settings 9 | secretKey: 'sk_YOUR_SECRET_KEY', // Your secret API KEY: https://dashboard.stripe.com/account/apikeys 10 | redirectUri: 'http://localhost:3000/connected', // https://dashboard.stripe.com/account/applications/settings 11 | 12 | port: 3000 13 | }; 14 | -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var app = express(); 5 | 6 | app.set('views', './views'); 7 | app.set('view engine', 'pug'); 8 | app.use(express.static('public')); 9 | 10 | module.exports = exports = app; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stripe-connect-node", 3 | "version": "0.0.1", 4 | "description": "A simple Node.js Stripe Connect example using OAuth 2", 5 | "private": true, 6 | "scripts": {}, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/floatingLomas/stripe-connect-node.git" 10 | }, 11 | "keywords": [ 12 | "stripe", 13 | "stripe-connect", 14 | "oauth" 15 | ], 16 | "author": "Jonathan Lomas ", 17 | "bugs": { 18 | "url": "https://github.com/floatingLomas/stripe-connect-node/issues" 19 | }, 20 | "homepage": "https://github.com/floatingLomas/stripe-connect-node", 21 | "dependencies": { 22 | "client-oauth2": "^2.2.0", 23 | "express": "^4.14.0", 24 | "pug": "^2.0.0-beta6", 25 | "stripe": "^4.10.0" 26 | }, 27 | "devDependencies": {} 28 | } 29 | -------------------------------------------------------------------------------- /public/global.css: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | body { 6 | /* Margin bottom by footer height */ 7 | margin-bottom: 60px; 8 | background-color: #fafafa; 9 | } 10 | body > .container { 11 | padding: 60px 15px 0; 12 | } 13 | .navbar-default { 14 | background-color:#fff; 15 | } 16 | .footer { 17 | position: absolute; 18 | bottom: 0; 19 | width: 100%; 20 | height: 60px; 21 | background-color: #fff; 22 | } 23 | .space-top { 24 | margin-top:20px; 25 | } 26 | dt { 27 | color: #777; 28 | } 29 | .shadow-sm { 30 | webkit-box-shadow: 0 2px 0 rgba(37,46,53,0.06); 31 | -moz-box-shadow: 0 2px 0 rgba(37,46,53,0.06); 32 | box-shadow: 0 2px 0 rgba(37,46,53,0.06); 33 | } 34 | .btn-xl { 35 | font-size:28px; 36 | padding:10px; 37 | font-weight: 300; 38 | } 39 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var CONFIG = require('./config'); 4 | 5 | var app = require('./lib/server'); 6 | var stripe = require('stripe')(CONFIG.secretKey); 7 | var OAuth = require('client-oauth2'); 8 | 9 | // Configure the OAuth 2.0 Client 10 | var oauth = new OAuth({ 11 | clientId: CONFIG.clientId, 12 | clientSecret: CONFIG.secretKey, 13 | 14 | scopes: ['read_write'], 15 | 16 | redirectUri: CONFIG.redirectUri, 17 | authorizationUri: 'https://connect.stripe.com/oauth/authorize', 18 | accessTokenUri: 'https://connect.stripe.com/oauth/token' 19 | }); 20 | 21 | // Get the home page: 22 | app.get('/', function(req, res) { 23 | res.render('index', { 24 | redirectUri: oauth.code.getUri() 25 | }); 26 | }); 27 | 28 | // Handle the redirect - this should match your CONFIG redirect's path: 29 | app.get('/connected', function(req, res) { 30 | if (req.query.error) return response.render('connected', { 31 | error: req.query.error 32 | }); 33 | 34 | // Use the Authorization Code to get a Token 35 | oauth.code.getToken(req.url).then(handleToken); 36 | 37 | // Go fetch the Account from the Token 38 | function handleToken(token) { 39 | stripe.account.retrieve(token.data.stripe_user_id, onAccount); 40 | } 41 | 42 | // Render the Account information 43 | function onAccount(error, account) { 44 | res.render('connected', { 45 | error: error, 46 | account: account 47 | }); 48 | } 49 | }); 50 | 51 | app.listen(CONFIG.port, function() { 52 | console.log('Listening on port', CONFIG.port); 53 | }); 54 | -------------------------------------------------------------------------------- /views/connected.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | include partials/head.pug 4 | 5 | body 6 | include partials/nav.pug 7 | 8 | .container 9 | if error 10 | .alert.alert-danger: strong #{error.error}: #{error.error_description} 11 | else 12 | .alert.alert-success: strong Successfully connected your Account! 13 | 14 | if account 15 | h2.page-header About your account 16 | 17 | .panel.panel-default.shadow-sm: .panel-body: .dl-horizontal 18 | dt #[i.fa.fa-cc-stripe] Account ID 19 | dd #{account.id} 20 | 21 | dt #[i.fa.fa-envelope] Email 22 | dd #{account.email} 23 | 24 | dt #[i.fa.fa-briefcase] Business Name 25 | dd #{account.business_name} 26 | 27 | dt #[i.fa.fa-globe] Country 28 | dd #{account.country} 29 | 30 | dt #[i.fa.fa-envelope] Email 31 | dd #{account.id} 32 | 33 | dt #[i.fa.fa-usd] Default Currency 34 | dd #{account.default_currency} 35 | 36 | dt #[i.fa.fa-briefcase] Display Name 37 | dd #{account.display_name} 38 | 39 | dt #[i.fa.fa-file-text] Statement Descriptor 40 | dd #{account.statement_descriptor} 41 | 42 | dt #[i.fa.fa-question-circle] Charges Enabled 43 | dd #{account.charges_enabled.toString()} 44 | 45 | dt #[i.fa.fa-question-circle] Transfers Enabled 46 | dd #{account.transfers_enabled.toString()} 47 | 48 | dt #[i.fa.fa-link] Website 49 | dd #{account.business_url} 50 | 51 | include partials/footer.pug 52 | -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | include partials/head.pug 4 | 5 | body 6 | include partials/nav.pug 7 | 8 | .container 9 | .page-header: h1 A Simple Stripe Connect PHP example 10 | 11 | p.lead This is a basic Stripe Connect example app built with Node.js, Express and an #[a( href="https://github.com/lelylan/simple-oauth2") OAuth 2.0 client]. 12 | 13 | p.lead This integration uses #[a(href="https://stripe.com/docs/connect/standalone-accounts") standalone accounts], so you can either create a new test account using #[a(href="https://stripe.com/docs/testing") some test data], or connect an existing account (in test mode). 14 | 15 | p: a.btn.btn-primary.btn-block.btn-xl( 16 | data-loading-text='Connecting...' 17 | href=redirectUri 18 | ) Connect to Stripe 19 | 20 | include partials/footer.pug 21 | -------------------------------------------------------------------------------- /views/partials/footer.pug: -------------------------------------------------------------------------------- 1 | footer.footer 2 | .container 3 | p.text-muted.text-center.space-top 4 | a(href='https://stripe.com/docs/connect') View Stripe Connect docs 5 | 6 | script(type='text/javascript'). 7 | $('.btn').on('click', function () { 8 | var $btn = $(this).button('loading') 9 | }); 10 | -------------------------------------------------------------------------------- /views/partials/head.pug: -------------------------------------------------------------------------------- 1 | head 2 | meta(charset='utf-8') 3 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 4 | meta(name='viewport', content='width=device-width, initial-scale=1') 5 | meta(name='description', content='') 6 | meta(name='author', content='') 7 | link(rel='icon', href='../../favicon.ico') 8 | title Simple Connect Node.js example 9 | script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js') 10 | script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js', integrity='sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS', crossorigin='anonymous') 11 | link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css', integrity='sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7', crossorigin='anonymous') 12 | link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css') 13 | link(rel='stylesheet', href='/global.css') 14 | // HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries 15 | //if lt IE 9 16 | script(src='https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js') 17 | script(src='https://oss.maxcdn.com/respond/1.4.2/respond.min.js') 18 | -------------------------------------------------------------------------------- /views/partials/nav.pug: -------------------------------------------------------------------------------- 1 | nav.navbar.navbar-default.navbar-fixed-top 2 | .container 3 | .navbar-header 4 | button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar') 5 | span.sr-only Toggle navigation 6 | span.icon-bar 7 | span.icon-bar 8 | span.icon-bar 9 | a.navbar-brand(href='/') Simple Connect Node.js 10 | #navbar.collapse.navbar-collapse.pull-right 11 | ul.nav.navbar-nav 12 | li 13 | a(href='/') Home 14 | li 15 | a(href='https://github.com/floatingLomas/stripe-connect-node') View on Github 16 | // /.nav-collapse 17 | --------------------------------------------------------------------------------