41a8c83313 | ||
---|---|---|
.github/workflows | ||
.vscode | ||
api | ||
docs | ||
public | ||
src | ||
.env.development | ||
.env.production | ||
.env.test | ||
.gitignore | ||
CODE_OF_CONDUCT.md | ||
LICENSE | ||
README.md | ||
SECURITY.md | ||
package.json | ||
yarn.lock |
README.md
Microsoft Open Source Code of Conduct
FrontendAppsells
Demo
Please click here to run the demo as it's hosted on Azure Static Web Apps.
This hack serves as a demo of the ledgers.js library. Please see use of oh$
in ./src/ledgers.js-react-widget/services/PaymentsService.js (UX widget) and ./api/SharedCode/overhide.js (back-end).
Introduction
This demo presents symbiosis between "Ledger Based Authorizations" and Azure's Static Web Apps.
The intent is to enable application developers to add free and for-pay authorization aspects to their single page applications--with a minimal backend integration, no concern for payment-gateways, no database work, hence without taking on responsibility of knowing their customers (GDPR compliant). We want to free app developers to focus on their features, not managing who is who, yet have a simple ability to make a profit from their creations.
The gist is to take public ledger authorization aspects from blockchains such as Ethereum, and make these concepts work for the majority of Web app customers holding regular US dollar credit cards. We want to enable app developers to charge for add-on features and subscriptions in their apps, without the developers having to stand up complex backends to interface with payment gateways and databases to keep tabs on their users.
This is an open-sourced demo of this "Ledger Based Authorizations" concept, leveraging the open-source "ledgers.js" library, to inspire that solutions with Azure Static Web Apps need not be made available freely without authorizations, or require AAD onboarding and overhead of payment-gateways. They can be simple public for-profit offerings. The intent is to give developers a path-forward on how they can make a profit from their creations.
If you consider a standard scalable e-commerce setup, it suggests that Web app developers integrate with third-party payment-gateways themselves. Here, we're offering a simple path forward without that burden. Not requisite--but a nice side benefit--it's a path forward that future proofs for payments with cryptos. Consider the green annotations below, applied on top of the standard model:
Some terms:
- ledger -- public table of payments between anonymized entities
- authN -- authentication (I am who I say I am)
- authZ -- authorization (I am allowed to do as much as I can prove I paid for)
- SPA -- Single Page Application; thick client Web application in the browser
This Repo
This project was created following below instructions to quickly create an Azure Static Web App for react:
Prerequisites:
- GitHub account
- Azure account
- VSCode with Azure Functions Extension installed.
It was amended with demo bits and the remuneration library and ledgers.js from overhide.
Overview
In this demo we have a React frontend and two Azure functions for the backend. The code we wrote in our app is under the "our demo code" label below:
See next section for more code details.
The ledgers.js-react-widget (React widget) provides login visuals to our users (in the browser) and updates the rest of our application as to whether the user authenticated and paid up for feature access.
The widget interacts with other visual components representing features in our app via a React context (LedgersWidgetPaymentsInfoContext, not shown). This context provides payment information. These other components, represented by FeatureComponent in our demo, are various paid add-ons and subscriptions. Since these are features that require authentication and payment, they interact with the ledgers.js-react-widget (via this injected context) for additional payments.
As these (FeatureComponent) features are used they call into our Azure functions backend to do feature specific business work. In addition to feature related parameters, the frontend provides the backend with information proving the user is authenticated (signature) and which ledger they authorized against (paid up). The Azure functions backend validates the provided signature and validates authorizations before performing feature work. The backend does the validations with two simple REST APIs.
This demo is rudimentary; the backend should really be extended to return a token for reuse on subsequent calls.
What We Accomplished as Application Developers
- we will get paid for our efforts
- we just plopped a simple widget into our frontend to give us a login + payments
- we spent very little effort on the backend to accomplish same
- this nimbleness and small footprint is very much in-line with the Azure Static Web Apps offering
- we didn't stand up a database for tracking our users (GDPR)
- the ledgers used are anonymous public ledgers, separating us as developers from being responsible for user's payment data
- if we choose to store feature data, it flows naturally that it can be kept anonymized in our feature data stores
- we use crypto concepts but allow our users to pay with credit cards in US dollars
- since we use crypto concepts, our application is crypto ready: we also allow payments with ethers
- this is completely secure in an introspectable user-agent such as a Web browser: no API keys, nothing to decompile
Using This in Your Azure Static Web Apps Projects
The basic steps to use what you see here in your projects:
- read through and follow the Azure Static Web Apps getting-started guide; after you should have:
- if you followed the above, you have your React (or other) app in GitHub and you're ready to instrument for payments
- if you want to get paid in Ethers, ensure to onboard onto Ethereum
- onboarding just means getting an Ethereum public/private key pair
- if you want to get paid in US dollars, ensure to onboard on overhide-ledger:
- configure your new application with your onboarded public addresses (both Ethereum and overhide)
- see all the
*_FEATURE_*_LEDGER_ADDRESS
Azure function configuration points in the Configuration section below - see the
/api/local.settings.json
file for local (F5 run) settings of same
- see all the
- use the
/api/SharedCode/overhide.js
backend library in your Azure functions, see the Azure Functions section below - use the
/src/ledgers.js-react-widget
widget in your frontend, see the UI Login Widget section below - ask for help on r/overhide
Next we dive a bit deeper into sections of code significant to this demo from a payments perspective.
Azure Functions
The Azure functions to make this solution work are very simple, they live in the /api
folder.
In /api/SharedCode/overhide.js
we have four tiny functions that call the two ledger APIs (is-signature-valid
and get-transactions
) from the back-end (Azure functions). The API calls use a bearer-token Authorization
header with a retrieved token. This is all that's needed for the back-end to validate authN and authZ. The APIs are detailed here for dollars and here for ethers.
See how this /api/SharedCode/overhide.js
is used in the RunFeature Azure function. This small utility file is all you need for your projects.
Notice that /api/package.json
includes a dependency on node-fetch
. Copy that into your projects. No need to worry about it past that--Azure Static Web Apps takes care of installing this dependency during deployment.
UI Login Widget
In /src/ledgers.js-react-widget
lives the React login widget:
To use this widget in your UI:
-
add
ledgers.js: 4.0.3
to you/package.json
React app dependencies,npm install
-
copy the
/src/ledgers.js-react-widget
folder to your project's components (will make it an npm component soon) -
notice that the
/src/ledgers.js-react-widget/LedgersWidget.js
depends on a context namedLedgersWidgetPaymentsInfoContext
; setup this context in your/src/App.js
-
in your
/src/Appjs
wire in the above widget (important callouts below):
...
import { LedgersWidgetPaymentsInfoContext } from './ledgers.js-react-widget/LedgersWidget';
...
class App extends React.Component {
...
this.state = {
paymentsInfo: {
updateApplicationStateFn: this.setPaymentsInfo,
setErrorFn: this.setError
},
...
setPaymentsInfo = (info) => {
this.setState({paymentsInfo: {...this.state.paymentsInfo, ...info}});
}
...
render() {
...
<LedgersWidgetPaymentsInfoContext.Provider value={this.state.paymentsInfo}>
...
</LedgersWidgetPaymentsInfoContext.Provider>
...
}
}
- The
LedgersWidgetPaymentsInfoContext
context is React's dependency-injection, it lets theLedgersWidget.js
provide authN and authZ state/functionality to the feature widgets:/src/components/FeatureComponent.js
. - Study use of
paymentInfo
in/src/components/FeatureComponent.js
- This
/src/components/FeatureComponent.js
provides feedback to the user regarding authN/authZ state with respect to the available features. It is where we call into the Azure functions back-end once allowed. - Notice that the back-end does it's own verification of permissions. The UI is there to provide payment feedback and allow payments.
DevOps Appendix
Azure Deployment
To deploy:
- follow https://docs.microsoft.com/en-ca/azure/static-web-apps/getting-started?tabs=react to connect your clone of this GitHub repo to your Azure Static Web Apps resource for this application
- this will update the
./.github/workflows
configuration with your connection's GitHub CI/CD Actions
- this will update the
- ensure all changes in this repo are pushed to GitHub
- ensure GitHub CI/CD Actions complete: (e.g. https://github.com/microsoft/frontend-appsells/actions)
- once GitHub CI/CD Actions complete, your build is automagically deployed
Configuration
In your Static Web App > Configuration create the following key value pairs.
Key | Value |
---|---|
APPINSIGHTS_INSTRUMENTATIONKEY | see 'Logging in Azure' below |
FREE_FEATURE_EXPIRY_MINUTES | 0 |
FREE_FEATURE_DOLLARS_COST | 0 |
FREE_FEATURE_DOLLARS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
FREE_FEATURE_ETHERS_COST | 0 |
FREE_FEATURE_ETHERS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
PAID_FEATURE_EXPIRY_MINUTES | 0 |
PAID_FEATURE_DOLLARS_COST | 2 |
PAID_FEATURE_DOLLARS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
PAID_FEATURE_ETHERS_COST | .006 |
PAID_FEATURE_ETHERS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
SUBSCRIPTION_FEATURE_EXPIRY_MINUTES | 2 |
SUBSCRIPTION_FEATURE_DOLLARS_COST | 3 |
SUBSCRIPTION_FEATURE_DOLLARS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
SUBSCRIPTION_FEATURE_ETHERS_COST | .009 |
SUBSCRIPTION_FEATURE_ETHERS_LEDGER_ADDRESS | 0x046c88317b23dc57F6945Bf4140140f73c8FC80F |
Most of the configuration is a fees schedule including ledger addresses of the recipient (developer of the app).
Note, 0x046c88317b23dc57F6945Bf4140140f73c8FC80F
is one of my public addresses on both the Ethereum blockchain and in the overhide-ledger: here I configured the same address for all features. I could have used multiple addresses, perhaps one per feature, and check authorization per address. Each address would be a feature SKU in that case.
A screenshot of the configuration when done:
Logging in Azure
- create an Application Insights resource
- take note of the new Application Insights instrumentation key
- create a new application setting key-value pair in the Static Web Apps > Configuration
- key:
APPINSIGHTS_INSTRUMENTATIONKEY
- value: from above
- key:
- inspect logs in the Application Insights > Logs, query:
traces | order by timestamp desc
Local Development
To run this solution in your local environment:
- install VSCode and Azure Functions Extention for VSCode
- in VSCode create a workspace with this repo
- in a separate console
npm install
dependencies - back in VSCode, start the local Azure Functions server by pressing F5
- in the separate console start the react server with
npm start
- navigate browser to http://localhost:3000
Configuration
See ./api/local.settings.json
npm start
Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.