mirror of https://github.com/lukechilds/docs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
11 KiB
293 lines
11 KiB
6 years ago
|
---
|
||
5 years ago
|
|
||
6 years ago
|
description: Single-page application with Blockstack
|
||
5 years ago
|
|
||
6 years ago
|
---
|
||
5 years ago
|
# Todo List
|
||
6 years ago
|
{:.no_toc}
|
||
6 years ago
|
|
||
|
In this tutorial, you build the code for and run a single-page application (SPA)
|
||
5 years ago
|
with Blockstack and React. Once the application is running, you take a tour
|
||
6 years ago
|
through the applications’ Blockstack functionality. You’ll learn how it manages
|
||
5 years ago
|
authentication using a Blockstack ID and how it stores information associated
|
||
6 years ago
|
with that ID using Blockstack Storage (Gaia).
|
||
|
|
||
|
* TOC
|
||
|
{:toc}
|
||
|
|
||
6 years ago
|
{% include note.html content="On macOS, Blockstack requires macOS High Sierra. This tutorial was written on macOS High Sierra 10.13.4. If you use a Windows or Linux system, you can still follow along. However, you will need to \"translate\" appropriately for your operating system. Additionally, this tutorial assumes you are accessing the Blockstack Browser web application via Chrome. The application you build will also work with a local installation and/or with browsers other than Chrome. " %}
|
||
6 years ago
|
|
||
6 years ago
|
## Before you begin
|
||
6 years ago
|
|
||
5 years ago
|
The application you build is a React application that is completely decentralized and server-less. While not strictly required to follow along, basic familiarity with React is helpful. When complete, the app is capable of the following:
|
||
6 years ago
|
|
||
|
* authenticating users using Blockstack
|
||
|
* posting new statuses
|
||
|
* displaying statuses in the user profile
|
||
|
* looking up the profiles and statuses of other users
|
||
|
|
||
6 years ago
|
For this tutorial, you will use the following tools:
|
||
|
|
||
|
* your workstation's command line
|
||
5 years ago
|
- Node.js v10 or higher is recommended the minimum supported version is Node.js v8.
|
||
6 years ago
|
|
||
6 years ago
|
The basic identity and storage services are provided by blockstack.js. To test the application, you need to have already registered a Blockstack ID.
|
||
|
|
||
5 years ago
|
### Verify you have Node.js and its tools installed
|
||
6 years ago
|
|
||
5 years ago
|
The tutorial relies on Node.js and its `npx` or `npm` tools. Before you begin, verify you have the correct version of Node.js and its tools installed.
|
||
6 years ago
|
|
||
|
```bash
|
||
5 years ago
|
$ node -v
|
||
|
v12.10.0
|
||
|
$ which npm npx
|
||
6 years ago
|
/usr/local/bin/npm
|
||
5 years ago
|
/usr/local/bin/npx
|
||
6 years ago
|
```
|
||
5 years ago
|
|
||
5 years ago
|
If you don't, make sure they are installed.
|
||
6 years ago
|
|
||
6 years ago
|
### Make sure you have a Blockstack ID
|
||
6 years ago
|
|
||
|
Finally, make sure you have [created at least one Blockstack ID]({{site.baseurl}}/browser/ids-introduction.html#create-an-initial-blockstack-id).
|
||
|
You’ll use this ID to interact with the application.
|
||
|
|
||
6 years ago
|
## Task 1: Install the code and retrieve the dependencies
|
||
6 years ago
|
|
||
5 years ago
|
You can clone the source code with `git` or [download and unzip the code from the repository](https://github.com/blockstack/blockstack-todos/archive/master.zip). These instructions assume you are cloning.
|
||
6 years ago
|
|
||
|
|
||
|
1. Install the code by cloning it.
|
||
|
|
||
|
```
|
||
6 years ago
|
$ git clone https://github.com/blockstack/blockstack-todos
|
||
6 years ago
|
```
|
||
|
|
||
|
2. Change to directory to the root of the code.
|
||
|
|
||
|
```
|
||
|
$ cd blockstack-todos
|
||
|
```
|
||
|
|
||
5 years ago
|
If you downloaded the zip file, the contents unzip into a `blockstack-todos-master` directory.
|
||
|
|
||
|
|
||
6 years ago
|
3. Use `npm` to install the dependencies.
|
||
6 years ago
|
|
||
|
|
||
|
```
|
||
6 years ago
|
$ npm install
|
||
6 years ago
|
```
|
||
|
|
||
5 years ago
|
The Todo application has a basic React structure. There are several configuration files but the central programming files are in the `src/components` directory:
|
||
6 years ago
|
|
||
5 years ago
|
| File | Description |
|
||
|
| ----------------------- | ------------------------------------------- |
|
||
|
| `index.js` | Application initialization. |
|
||
|
| `components/App.js ` | Code for handling the `authResponse`. |
|
||
|
| `components/Signin.js ` | Code for the initial sign on page. |
|
||
|
| `components/Profile.js` | Application data storage and user sign out. |
|
||
6 years ago
|
|
||
6 years ago
|
## Task 2: Sign into the application
|
||
6 years ago
|
|
||
|
The example application runs in a node server on your local host. In the this section, you start the application and interact with it.
|
||
|
|
||
|
1. Make sure you are in the root of the code base.
|
||
|
|
||
|
```bash
|
||
6 years ago
|
$ pwd
|
||
5 years ago
|
/Users/meepers/repos/blockstack-todos
|
||
6 years ago
|
```
|
||
6 years ago
|
|
||
|
This path will be different for you, but double-check the last part to ensure that you're in the directory into which you cloned and in which you ran `npm install`.
|
||
6 years ago
|
|
||
6 years ago
|
2. Start the application in your local environment.
|
||
6 years ago
|
|
||
6 years ago
|
```bash
|
||
5 years ago
|
$ npm run start
|
||
6 years ago
|
```
|
||
5 years ago
|
|
||
|
You should see output similar to the following:
|
||
6 years ago
|
|
||
5 years ago
|
```bash
|
||
|
Compiled successfully!
|
||
6 years ago
|
|
||
5 years ago
|
You can now view bs-todo in the browser.
|
||
|
|
||
|
http://127.0.0.1:3000/
|
||
6 years ago
|
|
||
6 years ago
|
Note that the development build is not optimized.
|
||
5 years ago
|
To create a production build, use npm run build.
|
||
|
```
|
||
|
|
||
|
2. Open your local browser to the `http://localhost:3000` URL.
|
||
6 years ago
|
|
||
6 years ago
|
You should see a simple application:
|
||
|
|
||
|
![](images/todo-sign-in.png)
|
||
|
|
||
6 years ago
|
3. Choose **Sign In with Blockstack**.
|
||
6 years ago
|
|
||
|
If you have already signed into Blockstack the application prompts you to select the ID to use. If you aren’t signed in, Blockstack prompts you to:
|
||
|
|
||
|
![](images/login-choice.png)
|
||
|
|
||
|
If the login to the application is successful, the user is presented with the application:
|
||
|
|
||
|
![](images/todo-app.png)
|
||
|
|
||
6 years ago
|
## Task 3: Learn about the sign in process
|
||
6 years ago
|
|
||
6 years ago
|
{% include sign_in.md %}
|
||
6 years ago
|
|
||
6 years ago
|
|
||
|
## Task 4: Decode the authRequest
|
||
|
|
||
6 years ago
|
To decode the token and see what information it holds:
|
||
|
|
||
|
1. Copy the `authRequest` string from the URL.
|
||
6 years ago
|
|
||
|
<img src="{{site.baseurl}}/develop/images/copy-authRequest.png" alt="">
|
||
|
|
||
6 years ago
|
2. Navigate to [jwt.io](https://jwt.io/).
|
||
|
3. Paste the full token there.
|
||
|
|
||
|
The output should look similar to below:
|
||
|
|
||
|
```json
|
||
|
{
|
||
6 years ago
|
"jti": "f65f02db-9f42-4523-bfa9-8034d8edf459",
|
||
|
"iat": 1555641911,
|
||
|
"exp": 1555645511,
|
||
|
"iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX",
|
||
6 years ago
|
"public_keys": [
|
||
6 years ago
|
"02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"
|
||
6 years ago
|
],
|
||
|
"domain_name": "http://localhost:8080",
|
||
|
"manifest_uri": "http://localhost:8080/manifest.json",
|
||
6 years ago
|
"redirect_uri": "http://localhost:8080",
|
||
|
"version": "1.3.1",
|
||
6 years ago
|
"do_not_include_profile": true,
|
||
|
"supports_hub_url": true,
|
||
|
"scopes": [
|
||
6 years ago
|
"store_write",
|
||
|
"publish_data"
|
||
6 years ago
|
]
|
||
|
}
|
||
|
```
|
||
|
|
||
6 years ago
|
The `iss` property is a decentralized identifier or `did`. This identifies the user and the user name to the application. The specific `did` is a `btc-addr`.
|
||
6 years ago
|
|
||
6 years ago
|
## Task 5: Under the covers in the sign in code
|
||
6 years ago
|
|
||
|
Now, go to the underlying `blockstack-todo` code you cloned or downloaded. Sign
|
||
|
in and sign out is handled in each of these files:
|
||
|
|
||
5 years ago
|
| File | Description |
|
||
|
| ----------------------- | ------------------------------------------- |
|
||
|
| `components/App.js ` | Code for handling the `authResponse`. |
|
||
|
| `components/Signin.js ` | Code for the initial sign on page. |
|
||
|
| `components/Profile.js` | Application data storage and user sign out. |
|
||
6 years ago
|
|
||
5 years ago
|
<!-- The `src/components/App.js` code configures an `AppConfig` object and then uses this to create a `UserSession`. Then, the application calls a [`redirectToSignIn()`](https://blockstack.github.io/blockstack.js#redirectToSignIn) function which generates the `authRequest` and redirects the user to the Blockstack authenticator: -->
|
||
6 years ago
|
|
||
5 years ago
|
The `src/components/App.js` code configures a `UserSession` and other `authOptions`, which are passed to the `Connect` component. The `Connect` component acts as a "provider" for the rest of your application, and essentially creates a re-usable configuration for you.
|
||
5 years ago
|
|
||
5 years ago
|
In the `src/components/Signin.js` component, we are then calling the `useConnect` hook. This hook returns many helper functions, one of which is `doOpenAuth`. Calling this method will being the authentication process. First, it injects a modal into your application, which acts as a way of "warming up" your user to Blockstack authentication. When the user continues, they are redirected to the Blockstack authenticator, where they can finish signing up.
|
||
5 years ago
|
|
||
5 years ago
|
```js
|
||
|
import React from 'react';
|
||
|
import { useConnect } from '@blockstack/connect';
|
||
|
|
||
|
export const Signin = () => {
|
||
|
const { doOpenAuth } = useConnect();
|
||
|
|
||
|
return (
|
||
|
<button
|
||
|
onClick={() => doOpenAuth()}
|
||
|
>
|
||
|
Sign In with Blockstack
|
||
|
</button>
|
||
|
)
|
||
|
};
|
||
6 years ago
|
```
|
||
|
|
||
5 years ago
|
Once the user authenticates, the application handles the `authResponse` in the `src/components/Profile.js` file. :
|
||
6 years ago
|
|
||
|
```js
|
||
5 years ago
|
...
|
||
|
componentWillMount() {
|
||
|
if (userSession.isSignInPending()) {
|
||
|
userSession.handlePendingSignIn().then((userData) => {
|
||
|
//if (!userData.username) {
|
||
|
// throw new Error('This app requires a username.')
|
||
|
//}
|
||
|
window.location = window.location.origin;
|
||
|
});
|
||
6 years ago
|
}
|
||
5 years ago
|
}
|
||
|
...
|
||
6 years ago
|
```
|
||
|
|
||
5 years ago
|
If [`isUserSignedIn()`](https://blockstack.github.io/blockstack.js/#isusersignedin) is true, the user was previously signed in so Blockstack pulls the data from the browser and uses it in our application. If the check on [`UserSession.isSignInPending()`](https://blockstack.github.io/blockstack.js/#issigninpending) is true, a previous `authResponse` was sent to the application but hasn't been processed yet. The `handlePendingSignIn()` function processes any pending sign in.
|
||
6 years ago
|
|
||
5 years ago
|
Signout is handled in `src/components/App.js`.
|
||
6 years ago
|
|
||
|
```js
|
||
5 years ago
|
handleSignOut(e) {
|
||
|
e.preventDefault();
|
||
|
userSession.signUserOut(window.location.origin);
|
||
6 years ago
|
}
|
||
6 years ago
|
```
|
||
|
|
||
|
The method allows the application creator to decide where to redirect the user upon Sign Out:
|
||
|
|
||
|
|
||
6 years ago
|
## Task 6: Work with the application
|
||
6 years ago
|
|
||
6 years ago
|
Now, trying adding a few items to the todo list. For example, try making a list of applications you want to see built on top of Blockstack:
|
||
6 years ago
|
|
||
|
![](images/make-a-list.png)
|
||
|
|
||
|
Each list is immediately stored in the Gaia Hub linked to your Blockstack ID.
|
||
5 years ago
|
For more information about the Gaia hub, [see the overview in this documentation]({{ site.baseurl }}/storage/overview.html#). Now that you have seen the application in action, dig into how it works.
|
||
6 years ago
|
|
||
|
|
||
6 years ago
|
## Task 7: Implement storage
|
||
6 years ago
|
|
||
5 years ago
|
Go to the underlying `blockstack-todo` code you cloned or downloaded. The application interactions with your Gaia Hub originate in the `src/components/Profile.js` file. First, examine where the changes to the Todos are processed in the `Profile.js` file.
|
||
|
|
||
|
The code needs to read the Todo items from the storage with the [`getFile()`](https://blockstack.github.io/blockstack.js/#getfile) method which returns a promise:
|
||
6 years ago
|
|
||
|
```js
|
||
5 years ago
|
loadTasks() {
|
||
|
const options = { decrypt: true };
|
||
|
this.props.userSession.getFile(TASKS_FILENAME, options)
|
||
|
.then((content) => {
|
||
|
if(content) {
|
||
|
const tasks = JSON.parse(content);
|
||
|
this.setState({tasks});
|
||
|
}
|
||
|
})
|
||
|
}
|
||
6 years ago
|
```
|
||
5 years ago
|
The `todos` data is retrieved from the promise. By default, the `getFile()` decrypts data for you. For more information on the available options, see the <a href="https://blockstack.github.io/blockstack.js/interfaces/getfileoptions.html" taraget="_blank">the blockstack.js</a> library for details on the `GetFileOptions` interface.
|
||
6 years ago
|
|
||
5 years ago
|
During the creation of a `todos`, a JSON object is passed in and the [`putFile()`](https://blockstack.github.io/blockstack.js/#putfile) method to store it in a Gaia Hub. By default, `putFile()` encrypts data when it stores it.
|
||
6 years ago
|
|
||
|
```js
|
||
5 years ago
|
saveTasks(tasks) {
|
||
|
const options = { encrypt: true };
|
||
|
this.props.userSession.putFile(TASKS_FILENAME, JSON.stringify(tasks), options);
|
||
|
}
|
||
6 years ago
|
```
|
||
|
|
||
|
|
||
|
## Summary
|
||
6 years ago
|
{:.no_toc}
|
||
6 years ago
|
|
||
|
You now have everything you need to construct complex applications complete with authentication and storage on the Decentralized Internet. Why not try coding [a sample application that accesses multiple profiles](blockstack_storage.html).
|
||
|
|
||
5 years ago
|
If you would like to explore the Blockstack APIs, you can visit the [Stacks Node API](https://core.blockstack.org/) documentation or the [Blockstack JS API](https://blockstack.github.io/blockstack.js).
|
||
6 years ago
|
|
||
5 years ago
|
Go forth and build!
|