Browse Source

Merge pull request #205 from moxiegirl/basic-sdk-docs

Add in basic information from Javascript
feat/clarity-updates
Moxiegirl 6 years ago
committed by GitHub
parent
commit
3254cbf68c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      _android/tutorial.md
  2. 2
      _browser/blockstack_storage.md
  3. 2
      _browser/browser-introduction.md
  4. 9
      _browser/hello-blockstack.md
  5. 6
      _browser/ids-introduction.md
  6. BIN
      _browser/images/navigation-top.png
  7. 202
      _browser/todo-list.md
  8. 7
      _data/navigation_learn.yml
  9. 140
      _develop/add_auth.md
  10. BIN
      _develop/images/copy-authRequest.png
  11. BIN
      _develop/images/signwithblockstack.png
  12. 196
      _develop/overview_auth.md
  13. 153
      _develop/profiles.md
  14. 112
      _develop/storage.md
  15. 2
      _develop/zero_to_dapp_3.md
  16. 2
      _develop/zero_to_dapp_3_win.md
  17. 19
      _includes/sign_in.md
  18. 2
      _ios/tutorial.md
  19. 18
      _storage/hello-hub-choice.md
  20. 332
      overview_auth.md

2
_android/tutorial.md

@ -223,7 +223,7 @@ In this section, you build an initial React.js application called
### Add a redirect end point to your application
When a user opens the webapp from the Blockstack browser on an Android phone,
When a user opens the webapp from the Blockstack Browser on an Android phone,
you want the web app to redirect the user to your Android application. The work
you do here will allow it.

2
_browser/blockstack_storage.md

@ -154,7 +154,7 @@ Leave your new application running and move onto the next section.
## Add the `publish_data` scope to sign in requests
Every app that uses Gaia storage must add itself to the user's `profile.json`
file. The Blockstack browser does this automatically when the `publish_data`
file. The Blockstack Browser does this automatically when the `publish_data`
scope is requested during authentication. For this application, the user files
stored on Gaia are made visible to others via the `apps` property in the user's
`profile.json` file.

2
_browser/browser-introduction.md

@ -17,7 +17,7 @@ website or buying an item.
## Understand the Blockstack Browser
Through the Blockstack browser application you can create an identity. An identity
Through the Blockstack Browser application you can create an identity. An identity
represents you as you interact with others through DApps. The Blockstack
Browser is itself, a simple DApp. It allows you to:

9
_browser/hello-blockstack.md

@ -258,11 +258,12 @@ several states the user can be in:
The application handles these situations as followed:
```js
if (blockstack.isUserSignedIn()) {
var profile = blockstack.loadUserData().profile
var userSession = new UserSession()
if (userSession.isUserSignedIn()) {
var profile = userSession.loadUserData().profile
showProfile(profile)
} else if (blockstack.isSignInPending()) {
blockstack.handlePendingSignIn().then(function(userData) {
} else if (userSession.isSignInPending()) {
userSession.handlePendingSignIn().then(function(userData) {
window.location = window.location.origin
})
}

6
_browser/ids-introduction.md

@ -142,14 +142,14 @@ not accessible by anyone.
The system prompts you for an email address. This email can be one you
entered previously or an entirely new one. Blockstack doesn't store this
address; it is used during your current Blockstack browser interaction to communicate
address; it is used during your current Blockstack Browser interaction to communicate
important information with you.
5. Enter an email and press **Next**.
The system prompts you for a password and its confirmation. This password
can be one you entered previously or an entirely new one. Write this password
down. You can use the password during your current Blockstack browser
down. You can use the password during your current Blockstack Browser
interaction to reveal your keychain or change your password. Blockstack does
not store this information past the session.
@ -179,7 +179,7 @@ not accessible by anyone.
The system prompts you for an email address. This email can be one you
entered previously or an entirely new one. Blockstack doesn't store this
address; it is used during your current Blockstack browser interaction to
address; it is used during your current Blockstack Browser interaction to
communicate important information with you.
5. Enter an email and press **Next**.

BIN
_browser/images/navigation-top.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 112 KiB

202
_browser/todo-list.md

@ -3,6 +3,7 @@ layout: learn
permalink: /:collection/:path.html
---
# Todo List Application Tutorial
{:.no_toc}
In this tutorial, you build the code for and run a single-page application (SPA)
with Blockstack and Vue.js. Once the application is running, you take a tour
@ -13,28 +14,38 @@ with that ID using Blockstack Storage (Gaia).
* TOC
{:toc}
{% include note.html content="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. " %}
{% 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. " %}
If you prefer a video, you can view <a href="https://www.youtube.com/embed/oyvg-h0obFw" target="\_blank">a video of the tutorial</a>.
## About this tutorial and the prerequisites you need
For this tutorial, we will use the following tools:
## Before you begin
* `npm` to manage dependencies and scripts
* `browserify` to compile node code into browser-ready code
* `blockstack.js` to authenticate the user and work with the user’s identity/profile information
At minimum, Blockstack requires macOS High Sierra. This tutorial was written for a user running macOS High Sierra 10.13.4. The application you build is a Vue.js application that is completely decentralized and server-less. While not strictly required to follow along, basic familiarity with Vue.js is helpful.
When complete, the app is capable of the following:
The application you build is a Vue.js application that is completely decentralized and server-less. While not strictly required to follow along, basic familiarity with Vue.js is helpful. When complete, the app is capable of the following:
* authenticating users using Blockstack
* posting new statuses
* displaying statuses in the user profile
* looking up the profiles and statuses of other users
For this tutorial, you will use the following tools:
* your workstation's command line
* `git` to clone the tutorial code
* `npm` to manage dependencies and scripts
The basic identity and storage services are provided by blockstack.js. To test the application, you need to have already registered a Blockstack ID.
### Verify you have git installed
This tutorial uses `git` to clone the tutorial code. Verify you have installed `git` using the `which` command to verify.
```bash
$ which git
/usr/local/bin/npm
```
### Verify you have npm installed
The tutorial relies on the `npm` dependency manager. Before you begin, verify you have installed `npm` using the `which` command to verify.
```bash
@ -43,11 +54,12 @@ $ which npm
```
If you don’t find `npm` in your system, [install it](https://www.npmjs.com/get-npm).
### Make sure you have a Blockstack ID
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.
## Install the application code and retrieve the dependencies
## Task 1: Install the code and retrieve the dependencies
You can clone the source code with `git` or [download and unzip the code from
the
@ -67,7 +79,7 @@ These instructions assume you are cloning.
$ cd blockstack-todos
```
2. Use `npm` to install the dependencies.
3. Use `npm` to install the dependencies.
```
@ -84,7 +96,7 @@ The Todo application has a basic Vue.js structure. There are several configurati
| `components/Dashboard.vue` | Application data storage and user sign out. |
## Sign into the application
## Task 2: Sign into the application
The example application runs in a node server on your local host. In the this section, you start the application and interact with it.
@ -97,17 +109,31 @@ The example application runs in a node server on your local host. In the this se
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`.
2. Start the application.
2. Start the application in your local environment.
```bash
$ npm run serve
```
$ npm run start
```
You should see output similar to the following:
```bash
98% after emitting CopyPlugin s
DONE Compiled successfully in 5854ms 7:34:28 PM
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.0.12:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
```
2. Open your local browser to the `http://localhost:8080` URL.
You should see a simple application:
![](images/todo-sign-in.png)
2. Choose **Sign In with Blockstack**.
3. Choose **Sign In with Blockstack**.
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:
@ -117,26 +143,19 @@ The example application runs in a node server on your local host. In the this se
![](images/todo-app.png)
## Understand the sign in process
## Task 3: Larn about the sign in process
Clicking the Sign In With Blockstack button brings up a modal that prompts you
to sign in with an existing ID or create a new ID. When Blockstack is provided
an ID, it generates an ephemeral key within the application. An ephemeral key is
generated for each execution of a key establishment process. This key is just
used for the particular instance of the application, in this case to sign a Sign
In request.
{% include sign_in.md %}
A Blockstack Core node also generates a public key token which is sent to the
browser as an `authRequest` from the browser to your core node. The signed
authentication request is sent to Blockstack through a JSON Web Token (JWT).
Blocktack passes the token in via a URL query string in the `authRequest`
parameter:
`https://browser.blockstack.org/auth?authRequest=j902120cn829n1jnvoa...`
## Task 4: Decode the authRequest
To decode the token and see what information it holds:
1. Copy the `authRequest` string from the URL.
<img src="{{site.baseurl}}/develop/images/copy-authRequest.png" alt="">
2. Navigate to [jwt.io](https://jwt.io/).
3. Paste the full token there.
@ -144,38 +163,29 @@ To decode the token and see what information it holds:
```json
{
"jti": "3i96e3ad-0626-4e32-a316-b243154212e2",
"iat": 1533136622,
"exp": 1533140228,
"iss": "did:btc-addr:1Nh8oQTunbEQWjrL666HBx2qMc81puLmMt",
"jti": "f65f02db-9f42-4523-bfa9-8034d8edf459",
"iat": 1555641911,
"exp": 1555645511,
"iss": "did:btc-addr:1ANL7TNdT7TTcjVnrvauP7Mq3tjcb8TsUX",
"public_keys": [
"0362173da080c6e1dec0653fa9a3eff5f5660546e387ce6c24u04a90c2fe1fdu73"
"02f08d5541bf611ded745cc15db08f4447bfa55a55a2dd555648a1de9759aea5f9"
],
"domain_name": "http://localhost:8080",
"manifest_uri": "http://localhost:8080/manifest.json",
"redirect_uri": "http://localhost:8080/",
"version": "1.2.0",
"redirect_uri": "http://localhost:8080",
"version": "1.3.1",
"do_not_include_profile": true,
"supports_hub_url": true,
"scopes": [
"store_write"
"store_write",
"publish_data"
]
}
```
>**Note**:
> * The `iss` property is a decentralized identifier or `did`. This identifies you and your name to the application. The specific `did` is a `btc-addr`.
> * The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in [Javascript](https://github.com/blockstack/jsontokens-js) and [Ruby](https://github.com/blockstack/ruby-jwt-blockstack) available on the Blockstack Github to allow you to work with these tokens.
When the Blockstack node receives the `authRequest`, it generates a session token
and returns an authentication response to the application. This response is
similar to the `authRequest` above in that the `authResponse` includes a private key
intended only for the application. This allows the application to encrypt data
on your personal Blockstack storage.
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`.
After the completion of this process, the user is logged in.
## Under the covers in the sign in code
## Task 5: Under the covers in the sign in code
Now, go to the underlying `blockstack-todo` code you cloned or downloaded. Sign
in and sign out is handled in each of these files:
@ -186,50 +196,55 @@ in and sign out is handled in each of these files:
| `Landing.vue ` | Generates the `authRequest`. |
| `Dashboard.vue` | Handles sign out. |
The `src/components/Landing.vue` code calls a [`redirectToSignIn()`](https://blockstack.github.io/blockstack.js#redirectToSignIn) function which generates the `authRequest` and redirects the user to the Blockstack authenticator:
The `src/components/Landing.vue` 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:
```js
signIn () {
const blockstack = this.blockstack
blockstack.redirectToSignIn()
}
signIn () {
const appConfig = new this.blockstack.AppConfig(['store_write', 'publish_data'])
const UserSession = new this.blockstack.UserSession({ appConfig: appConfig })
UserSession.redirectToSignIn()
}
```
Once the user authenticates, the application handles the `authResponse` in the `src/App.vue` file. :
```js
if (blockstack.isUserSignedIn()) {
this.user = blockstack.loadUserData().profile
} else if (blockstack.isSignInPending()) {
blockstack.handlePendingSignIn()
.then((userData) => {
window.location = window.location.origin
})
}
mounted () {
const UserSession = this.UserSession
if (UserSession.isUserSignedIn()) {
this.userData = UserSession.loadUserData()
this.user = new this.blockstack.Person(this.userData.profile)
this.user.username = this.userData.username
} else if (UserSession.isSignInPending()) {
UserSession.handlePendingSignIn()
.then((userData) => {
window.location = window.location.origin
})
}
},
```
If [`blockstack.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 [`blockstack.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.
If [`blockstack.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 [`blockstack.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.
Signout is handled in `src/components/Dashboard.vue`.
```js
signOut () {
this.blockstack.signUserOut(window.location.href)
}
signOut () {
this.UserSession.signUserOut(window.location.href)
}
```
The method allows the application creator to decide where to redirect the user upon Sign Out:
## Working with the application
## Task 6: Work with the application
Now, trying adding a few itmes to the todo list. For example, try making a list of applications you want to see built on top of Blockstack:
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:
![](images/make-a-list.png)
Each list is immediately stored in the Gaia Hub linked to your Blockstack ID.
For more information about the Gaia hub, see the [hub
repository](https://github.com/blockstack/gaia). You can fetch the `todos.json`
For more information about the Gaia hub, [see the overview in this documentation]({{ site.baseurl }}/storage/overview.html#). You can fetch the `todos.json`
file you just added by opening the Javascript console and running the following
command:
@ -281,7 +296,7 @@ using the Javascript console, the results reflect your change. Look for `"comple
Now that you have seen the application in action, dig into how it works.
## Implementing storage
## Task 7: Implement storage
Go to the underlying `blockstack-todo` code you cloned or downloaded. The
application interactions with your Gaia Hub originate in the
@ -289,35 +304,37 @@ application interactions with your Gaia Hub originate in the
Todos are processed:
```js
todos: {
handler: function (todos) {
const blockstack = this.blockstack
// encryption is now enabled by default
return blockstack.putFile(STORAGE_FILE, JSON.stringify(todos))
watch: {
todos: {
handler: function (todos) {
const UserSession = this.UserSession
// encryption is now enabled by default
return UserSession.putFile(STORAGE_FILE, JSON.stringify(todos))
},
deep: true
}
},
deep: true
}
```
The `todos` JSON object is passed in and the
[`blockstack.putFile()`](https://blockstack.github.io/blockstack.js/#putfile)
[`blockstack.UserSession.putFile()`](https://blockstack.github.io/blockstack.js/#putfile)
method to store it in a Gaia Hub.
The code needs to read the Todo items from the storage with the [`blockstack.getFile()`](https://blockstack.github.io/blockstack.js/#getfile) method which returns a promise:
The code needs to read the Todo items from the storage with the [`blockstack.UserSession.getFile()`](https://blockstack.github.io/blockstack.js/#getfile) method which returns a promise:
```js
fetchData () {
const blockstack = this.blockstack
blockstack.getFile(STORAGE_FILE) // decryption is enabled by default
.then((todosText) => {
var todos = JSON.parse(todosText || '[]')
todos.forEach(function (todo, index) {
todo.id = index
})
this.uidCount = todos.length
this.todos = todos
})
const UserSession = this.UserSession
UserSession.getFile(STORAGE_FILE) // decryption is enabled by default
.then((todosText) => {
var todos = JSON.parse(todosText || '[]')
todos.forEach(function (todo, index) {
todo.id = index
})
this.uidCount = todos.length
this.todos = todos
})
},
```
@ -325,6 +342,7 @@ The `todos` data is retrieved from the promise.
## Summary
{:.no_toc}
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).

7
_data/navigation_learn.yml

@ -3,6 +3,13 @@
- develop/dapp_principles
- core/faq_developer
- title: Building Blocks
- docs:
- develop/overview_auth
- develop/add_auth
- develop/storage
- develop/profiles
- title: Try it! Zero to DApp
docs:
- develop/zero_to_dapp_1

140
_develop/add_auth.md

@ -0,0 +1,140 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Add Auth to your DApp
{:.no_toc}
The way you can add Blockstack Auth to your DApp depends on whether your
app is a modern decentralized Blockstack App where code runs client-side without
trusted servers or a legacy client-server app where a server is trusted.
* TOC
{:toc}
## Authentication in Client-side apps
This method is appropriate for decentralized client-side apps where the user's
zone of trust &mdash; the parts of the app that the user is trusting &mdash; begins and ends
with the code running on their own computer. In apps like these, any code the
app interacts with that's not on their own computer such as external servers
does not need to know who they are.
[Blockstack.js](https://blockstack.github.io/blockstack.js/) provides API
methods that help you to implement Blockstack Authentication in your client-side
app.
### Default flow
The preferred way to implement authentication in these apps is to use the
default flow. This flow encapsulates authentication behind a few function
calls and makes it very fast to get up and running.
The default process use these four functions:
- <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#redirecttosignin" target="_blank">UserSession.redirectToSignIn</a>
- <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#issigninpending" target="_blank">UserSession.isSignInPending</a>
- <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#handlependingsignin" target="_blank">UserSession.handlePendingSignIn</a>
- <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#loaduserdata" target="_blank">UserSession.loadUserData</a>
When your app wants to start the sign in process, typically when the user clicks
a **Sign in with Blockstack** button, your app will call the `UserSession.redirectToSignIn`.
This creates an ephemeral transit key, stores it in the web browser's
`localStorage`. Then, the function is used to create an authentication request token. The Blockstack Browser
redirects the user to the Blockstack Browser to approve the sign in request.
When a user approves a sign in request, the Blockstack Browser returns a signed `authResponse` token to the `redirectURI` specified in `UserSession.redirectToSignIn`.
To check for the presence of this token, your app should call `UserSession.isSignInPending`. If this returns `true`, the app should then call `UserSession.handlePendingSignIn`. This decodes the token, returns the signed-in-user's data, and simultaneously storing it to `localStorage` so that it can be retrieved later with `loadUserData`.
```js
import * as blockstack from 'blockstack'
var userSession = new UserSession()
if (userSession.isSignInPending()) {
userSession.handlePendingSignIn()
.then(userData => {
const profile = userData.profile
})
}
```
By default, these method use the `store_write` scope which allows the DApp to read the user profile and read/write user data for the DApp. To specify a different scope, use a <a href="https://blockstack.github.io/blockstack.js/classes/appconfig.html" target="\_blank">AppConfig</a> object.
### Custom flows
Alternatively, you can generate your own transit private key and/or
authentication request token using the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#makeauthrequest" target="_blank">UserSession.makeAuthRequest</a> function. This function gives you more control over the authentication experience. For example, you can change the sign in experience so that it prompts users who have not yet created a Blockstack identity, to choose a hub URL.
The `makeAuthRequest()` method takes the following parameters:
<dl class="uk-description-list">
<dt class="uk-text-lowercase">
<code>transitPrivateKey(String = generateAndStoreTransitKey())</code>
</dt>
<dd>A HEX encoded transit private key.</dd>
<dt class="uk-text-lowercase">
<code>redirectURI(String = `${window.location.origin}/`)</code>
</dt>
<dd>Location to redirect the user to after sign in approval.</dd>
<dt class="uk-text-lowercase">
<code>manifestURI(String = `${window.location.origin}/manifest.json`)</code>
</dt>
<dd>
Location of this app's manifest file.
</dd>
<dt class="uk-text-lowercase">
<code>scopes (Array = DEFAULT_SCOPE)</code>
</dt>
<dd>The permissions this app is requesting.</dd>
<dt class="uk-text-lowercase">
<code>appDomain(String = window.location.origin)</code>
</dt>
<dd>The origin of this app.</dd>
<dt class="uk-text-lowercase">
<code>expiresAt(Number = nextHour().getTime())</code>
</dt>
<dd>The time at which this request is no longer valid.</dd>
<dt class="uk-text-lowercase">
<code>extraParams(Object = {})</code>
</dt>
<dd>Any extra parameters to pass to the authenticator. Use this to pass options that aren't part of the Blockstack authentication specification, but might be supported by special authenticators.</dd>
</dl>
For example, you could use the following code to generate an authentication
request on `https://alice.example.com` or `https://bob.example.com` for an app
running on origin `https://example.com`.
```js
const transitPrivateKey = generateAndStoreTransitKey()
const redirectURI = 'https://example.com/authLandingPage'
const manifestURI = 'https://example.com/manifest.json'
const scopes = ['scope_write', 'publish_data']
const appDomain = 'https://example.com'
const authRequest = makeAuthRequest(transitPrivateKey, redirectURI, manifestURI, scopes, appDomain)
redirectToSignInWithAuthRequest(authRequest)
```
## Authentication in client-server apps
{% include note.html content="Client-server authentication requires using a library written in the
language of your server app. There are private methods in blockstack.js that can
be accomplish this on node.js server apps, but they are not currently part of
our public, supported API." %}
Using Blockstack Authentication in client-server apps is very similar to
client-side apps. You generate the authentication request using the same code in
the client as described above.
The main difference is that you need to verify the authentication response token
on the server after the user approves sign in to your app.
For an example of how verification can be done server side, take a look at the
[blockstack-ruby](https://github.com/blockstack/blockstack-ruby#to-verify-an-auth-response)
library.

BIN
_develop/images/copy-authRequest.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
_develop/images/signwithblockstack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

196
_develop/overview_auth.md

@ -0,0 +1,196 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Understand Blockstack Auth
{:.no_toc}
Blockstack Auth provides single sign on and authentication without third parties or remote servers. On this page, you'll get an overview of authentication from an developer and user perspective. The following topics are covered:
* TOC
{:toc}
## User experience flow
Blockstack Auth is a bearer token-based authentication system. From an application user's perspective, Blockstack authentication is similar to legacy third-party authentication techniques that they're familiar with. Applications present users with a **Sign in with Blockstack** button.
![](images/signwithblockstack.png)
Assume a user, Alice, clicks the **Sign in with Blockstack** button on an app. She is
redirected to her copy of the Blockstack Browser. The Blockstack sign-in dialog a user sees depends on
whether the user already has an existing Blockstack Browser session for their current device.
<img src="images/kingdom_notin.png" alt="">
Signing in with an identity is the means by which the user grants the DApp access. Access depends on the scope requested by the DApp. The default `store_write` scope allows the DApp to read the user profile and read/write user data for the DApp. Data is encrypted at a unique URL on a Gaia storage hub.
Alice can choose to authenticate and sign into the DApp with one of her Blockstack IDs by selecting the
ID. The Blockstack Browser shows Alice an approval dialog with information about the access the DApp requests:
* The origin your app was served from
* Your app's name
* Your app's logo
* The types of permissions and data your app is requesting
When she chooses an ID (or creates a new one), Alice is redirected back to the DApp where she is logged in.
## DApp authentication flow
{% include sign_in.md %}
## Scopes
Scopes define the permissions requested from, and that a user accepts, through the sign-in dialog.
DApps may request any of the following scopes:
| Scope | Definition|
|---|---|
| `store_write` | Read and write data to the user's Gaia hub in an app-specific storage bucket. |
| `publish_data` | Publish data so that other users of the app can discover and interact with the user. |
| `email` | Requests the user's email if available. |
The permissions scope should be specified through the <a href="https://blockstack.github.io/blockstack.js/classes/appconfig.html" target="\_blank">AppConfig</a> object. If no `scopes` array is provided to the `redirectToSignIn` or `makeAuthRequest`
functions, the default is to request `['store_write']`.
## blockstack: custom protocol handler
The `blockstack:` custom protocol handler is how Blockstack apps send their authentication requests to the Blockstack Browser. Users can have a Blockstack Browser installed locally on their device or they can use the web version of the Blockstack Browser. If the Blockstack Browser is installed on a user's computer, it registers itself as the handler for the `blockstack:` customer protocol.
When an application calls
[`redirectToSignIn`](http://blockstack.github.io/blockstack.js/index.html#redirecttosignin)
or
[`redirectToSignInWithAuthRequest`](http://blockstack.github.io/blockstack.js/index.html#redirecttosigninwithauthrequest),
blockstack.js checks if a `blockstack:` protocol handler is installed and, if so,
redirects the user to `blockstack:<authRequestToken>`. This passes the
authentication request token from the app to the local Blockstack Browser. If the local Blockstack Browser is not installed, the call is directed to the web version of the Blockstack Browser.
## Manifest file
Blockstack apps have a manifest file. This file is based on the [W3C web app manifest specification](https://w3c.github.io/manifest/). The following is an example manifest file.
```
{
"name": "Todo App",
"start_url": "http://blockstack-todos.appartisan.com",
"description": "A simple todo app build on blockstack",
"icons": [{
"src": "http://blockstack-todos.appartisan.com/logo.png",
"sizes": "400x400",
"type": "image/png"
}]
}
```
The Blockstack Browser retrieves the manifest file from the app during the
authentication process and displays the information in it such as the
app `name` and to the user during sign in. The location of the app manifest file is specific
in the authentication request token and **must** be on the same origin as the app
requesting authentication.
The manifest file **must** have [Cross-origin resource sharing (CORS) headers](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) that allow the manifest file to be fetched from any arbitrary source. This usually means returning a header like this:
```
Access-Control-Allow-Origin: *
```
How you implement CORS depends in part on which platform/service you use to serve your application. For example, Netlify and Firebase have two different ways of configuring CORS. Consult your vendor documentation for more information.
## Key pairs
Blockstack Auth makes extensive use of public key cryptography. Blockstack uses ECDSA with the `secp256k1` curve. The following sections describe the three public-private key pairs used in the authentication process:
* how they're generated
* where they're used
* to whom the private key is disclosed
### Transit private key
The transit private is an ephemeral key that is used to encrypt secrets that
need to be passed from the Blockstack Browser to the app during the
authentication process. It is randomly generated by the app at the beginning of
the authentication response.
The public key that corresponds to the transit private key is stored in a single
element array in the `public_keys` key of the authentication request token. The
Blockstack Browser encrypts secret data such as the app private key using this
public key and sends it back to the app when the user signs in to the app. The
transit private key signs the app authentication request.
### Blockstack ID Identity address private key
The identity address private key is derived from the user's keychain phrase and
is the private key of the Blockstack ID that the user chooses to use to sign in
to the app. It is a secret owned by the user and never leaves the user's
instance of the Blockstack Browser.
This private key signs the authentication response token for an app to indicate that the user approves sign in to that app.
### App private key
The app private key is an app-specific private key that is generated from the
user's identity address private key using the `domain_name` as input. It is
deterministic in that for a given Blockstack ID and `domain_name`, the same
private key is generated each time.
The app private key is securely shared with the app on each authentication, encrypted by the Blockstack Browser with the transit public key.
## JSON Web Token signatures
Both the `authRequest` and the `authResponse` tokens are [JSON Web Tokens](https://jwt.io/), and they are passed via URL query strings.
Blockstack's authentication tokens are based on the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519)
with additional support for the `secp256k1` curve used by Bitcoin and many other
cryptocurrencies.
This signature algorithm is indicated by specifying `ES256K` in the token's
`alg` key, specifying that the JWT signature uses ECDSA with the secp256k1
curve. Blockstack provide both [JavaScript](https://github.com/blockstack/jsontokens-js)
and
[Ruby](https://github.com/blockstack/ruby-jwt-blockstack/tree/ruby-jwt-blockstack)
JWT libraries with support for this signing algorithm.
{% include note.html content="The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in <a href='https://github.com/blockstack/jsontokens-js'>Javascript</a> and <a href='https://github.com/blockstack/ruby-jwt-blockstack'>Ruby</a> available on the Blockstack Github to allow you to work with these tokens." %}
### Example: authRequest payload schema
``` JavaScript
const requestPayload = {
jti, // UUID
iat, // JWT creation time in seconds
exp, // JWT expiration time in seconds
iss, // legacy decentralized identifier generated from transit key
public_keys, // single entry array with public key of transit key
domain_name, // app origin
manifest_uri, // url to manifest file - must be hosted on app origin
redirect_uri, // url to which browser redirects user on auth approval - must be hosted on app origin
version, // version tuple
do_not_include_profile, // a boolean flag asking browser to send profile url instead of profile object
supports_hub_url, // a boolean flag indicating gaia hub support
scopes // an array of string values indicating scopes requested by the app
}
```
### Example: authResponse payload schema
```JavaScript
const responsePayload = {
jti, // UUID
iat, // JWT creation time in seconds
exp, // JWT expiration time in seconds
iss, // legacy decentralized identifier (string prefix + identity address) - this uniquely identifies the user
private_key, // encrypted private key payload
public_keys, // single entry array with public key
profile, // profile object or null if passed by profile_url
username, // blockstack id username (if any)
core_token, // encrypted core token payload
email, // email if email scope is requested & email available
profile_url, // url to signed profile token
hubUrl, // url pointing to user's gaia hub
version // version tuple
}
```

153
_develop/profiles.md

@ -0,0 +1,153 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Work with Profiles
{:.no_toc}
You can use the blockstack.js library to create and register an ID on the Stacks blockchain. This section describes the `Profile` object and contains the following topics:
* TOC
{:toc}
## About profiels
Profile data is stored using Gaia on the user's selected storage provider. An example of a `profile.json` file URL using Blockstack provided storage:
```
https://gaia.blockstack.org/hub/1EeZtGNdFrVB2AgLFsZbyBCF7UTZcEWhHk/profile.json
```
Follow these steps to create and register a profile for a Blockstack ID:
1. Create a JSON profile object
2. Split up the profile into tokens, sign the tokens, and put them in a token file
3. Create a zone file that points to the web location of the profile token file
Accounts can have one or more proofs. Proofs are stored under the `account` key in the user's profile data
```js
"account": [
{
"@type": "Account",
"service": "twitter",
"identifier": "naval",
"proofType": "http",
"proofUrl": "https://twitter.com/naval/status/12345678901234567890"
}
]
```
## Create a profile
```es6
const profileOfNaval = {
"@context": "http://schema.org/",
"@type": "Person",
"name": "Naval Ravikant",
"description": "Co-founder of AngelList"
}
```
## Sign a profile as a single token
```es6
import { makeECPrivateKey, wrapProfileToken, Person } from 'blockstack'
const privateKey = makeECPrivateKey()
const person = new Person(profileOfNaval)
const token = person.toToken(privateKey)
const tokenFile = [wrapProfileToken(token)]
```
## Verify an individual token
```js
import { verifyProfileToken } from 'blockstack'
try {
const decodedToken = verifyProfileToken(tokenFile[0].token, publicKey)
} catch(e) {
console.log(e)
}
```
## Recover a profile from a token file
```js
const recoveredProfile = Person.fromToken(tokenFile, publicKey)
```
## Validate profile schema
```js
const validationResults = Person.validateSchema(recoveredProfile)
```
## Validate a proof
```es6
import { validateProofs } from 'blockstack'
const domainName = "naval.id"
validateProofs(profile, domainName).then((proofs) => {
console.log(proofs)
})
```
## How proofs are validated
The `validateProofs` function checks each of the proofs listed in the
profile by fetching the proof URL and verifying the proof message. Currently supported proof validation services:
- Facebook
- Twitter
- Instagram
- LinkedIn
- Hacker News
- GitHub
The proof message must be of the form:
```
Verifying my Blockstack ID is secured with the address
1EeZtGNdFrVB2AgLFsZbyBCF7UTZcEWhHk
```
The proof message also must appear in the required location on the
proof page specific to each type of social media account.
The account from which the proof message is posted must match exactly
the account identifier/username claimed in the user profile. The
`validateProofs` function will check this in the body of the proof or
in the proof URL depending on the service.
## Adding additional social account validation services
The `Service` class can be extended to provide proof validation service
to additional social account types. You will need to override the
`getProofStatement(searchText: string)` method which parses the proof
body and returns the proof message text. Additionally, the identifier
claimed should be verified in the proof URL or in the body by implementing
`getProofIdentity(searchText: string)` and setting `shouldValidateIdentityInBody()`
to return true.
The following snippet uses the meta tags in the proof page to retrieve the proof message.
```js
static getProofStatement(searchText: string) {
const $ = cheerio.load(searchText)
const statement = $('meta[property="og:description"]')
.attr('content')
if (statement !== undefined && statement.split(':').length > 1) {
return statement.split(':')[1].trim().replace('“', '').replace('”', '')
} else {
return ''
}
}
```

112
_develop/storage.md

@ -0,0 +1,112 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Work with Storage
{:.no_toc}
The Blockstack Platform stores application data in the Gaia Storage System. Transactional metadata is stored on the Blockstack blockchain and user application data is stored in Gaia storage. Storing data off of the blockchain ensures that Blockstack applications can provide users with high performance and high availability for data reads and writes without introducing central trust parties.
* TOC
{:toc}
{% include note.html content="<ul> <li>Blockstack Gaia Storage APIs and on-disk format will change in upcoming pre-releases breaking backward compatibility. File encryption is currently opt-in on a file by file basis.</li> <li>Certain storage features such as collections are not implemented in the current version. These features will be rolled out in future updates.</li> </ul>" %}
## Creating a file
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#putfile" target="_blank">UserSession.putFile</a>
```JavaScript
let options = {
encrypt: false
}
blockstack.UserSession.putFile("/hello.txt", "hello world!", options)
.then(() => {
// /hello.txt exists now, and has the contents "hello world!".
})
```
## Creating an encrypted file
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#putfile" target="_blank"></a>
```JavaScript
let options = {
encrypt: true
}
blockstack.UserSession.putFile("/message.txt", "Secret hello!", options)
.then(() => {
// message.txt exists now, and has the contents "hello world!".
})
```
## Reading a file
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#getfile" target="_blank"></a>
```JavaScript
let options = {
decrypt: false
}
blockstack.UserSession.getFile("/hello.txt", options)
.then((fileContents) => {
// get the contents of the file /hello.txt
assert(fileContents === "hello world!")
});
```
## Reading an encrypted file
You use the <a href="" target="_blank"></a>
```JavaScript
let options = {
decrypt: true
}
blockstack.UserSession.getFile("/message.txt", options)
.then((fileContents) => {
// get & decrypt the contents of the file /message.txt
assert(fileContents === "Secret hello!")
});
```
## Reading another user's unencrypted file
In order for files to be publicly readable, the app must request
the `publish_data` scope during authentication.
```JavaScript
let options = {
user: 'ryan.id', // the Blockstack ID of the user for which to lookup the file
app: 'http://BlockstackApp.com' // origin of the app this file is stored for
}
var userSession = new UserSession()
userSession.putFile("/hello.txt", "hello world!", options)
.then((fileContents) => {
// get the contents of the file /message.txt
assert(fileContents === "hello world!")
});
```
## Delete a file
You use the <a href="https://blockstack.github.io/blockstack.js/classes/usersession.html#deletefile" target="_blank">UserSession.deleteFile</a> from the application's data store.
```JavaScript
blockstack.deleteFile("/hello.txt")
.then(() => {
// /hello.txt is now removed.
})
```
## Related Information
{:.no_toc}
To learn more about the guarantees provided by Gaia, see [Storage write and read]({{ site.baseurl }}/storage/write-to-read.html#)

2
_develop/zero_to_dapp_3.md

@ -102,7 +102,7 @@ signed into the DApp previously. If not, it opens the `Landing.js` page. This
page offers the user an opportunity to **Sign in to Blockstack**.
Clicking the button ends up calling the `redirectToSignIn()` method which generates an
authentication request and redirects the user to the Blockstack browser to
authentication request and redirects the user to the Blockstack Browser to
approve the sign in request. The actual Blockstack sign-in dialog depends on
whether the user already has an existing session in the Blockstack Browser.

2
_develop/zero_to_dapp_3_win.md

@ -102,7 +102,7 @@ signed into the DApp previously. If not, it opens the `Landing.js` page. This
page offers the user an opportunity to **Sign in to Blockstack**.
Clicking the button ends up calling the `redirectToSignIn()` method which generates an
authentication request and redirects the user to the Blockstack browser to
authentication request and redirects the user to the Blockstack Browser to
approve the sign in request. The actual Blockstack sign-in dialog depends on
whether the user already has an existing session in the Blockstack Browser.

19
_includes/sign_in.md

@ -0,0 +1,19 @@
For an application developer, the application flow is similar to the typical client-server flow used by centralized sign in services (e.g., OAuth). However, with Blockstack, the authentication flow happens entirely client-side.
A decentralized application (DApp) and the Blockstack Browser communicate during the authentication flow by passing back and forth two tokens. The requesting application sends the Blockstack Browser an `authRequest` token. Once a user approves a sign-in, the Blockstack Browser responds to the application with an `authResponse` token. These tokens are <a href="https://jwt.io/" target="\_blank">JSON Web Tokens</a>, and they are passed via URL query strings.
![](/storage/images/app-sign-in.png)
When a user chooses to **Sign in with Blockstack** on a DApp, it calls the `redirectToSignIn()` method which sends an `authRequest` to the Blockstack Browser. Blockstack passes the token in via a URL query string in the `authRequest` parameter:
`https://browser.blockstack.org/auth?authRequest=j902120cn829n1jnvoa...`
When the Blockstack Browser receives the request, it generates an (`authResponse`) token to the application using an _ephemeral transit key_ . The ephemeral transit key is just used for the particular instance of the application, in this case, to sign the `authRequest`. The application stores the ephemeral transit key during the request generation. The public portion of the transit key is passed in the `authRequest` token. The Blockstack Browser uses the public portion of the key to encrypt an _app-private key_ which is returned via the `authResponse`.
During sign in, the Blockstack Browser generates the app-private key from the user's _identity-address private_ key and the application's `appDomain`. The app private key serves three functions:
* It is used to create the credentials that give an app access to the Gaia storage bucket for that specific app.
* It is used in the end-to-end encryption of files stored for the app in the user's Gaia storage.
* It serves as a cryptographic secret that apps can use to perform other cryptographic functions.
Finally, the app private key is deterministic, meaning that for a given user ID and domain name, the same private key is generated each time.

2
_ios/tutorial.md

@ -225,7 +225,7 @@ In this section, you build an initial React.js application called
### Add a redirect end point to your application
When a user opens the webapp from the Blockstack browser on an iOS phone,
When a user opens the webapp from the Blockstack Browser on an iOS phone,
you want the web app to redirect the user to your iOS application. The work
you do here will allow it.

18
_storage/hello-hub-choice.md

@ -147,15 +147,20 @@ To replace the default login, do the following:
1. Using your favorite editor, open the `public/app.js` file.
2. Locate the `redirectToSignIn()` method at line 4.
3. Replace `redirectToSignIn()` method with the `blockstack.redirectToSignInWithAuthRequest(authRequest)` method.
3. Replace `redirectToSignIn()` method with the `blockstack.UserSession.redirectToSignInWithAuthRequest(authRequest)` method.
```javascript
var userSession = new UserSession()
userSession.redirectToSignInWithAuthRequest(authRequest)
```
The `authRequest` is the authentication request generated by `makeAuthRequest()` method.
4. Immediately above the method you just added and below the `event.preventDefault()` method, construct a String `const` for the `authRequest`:
```
const authRequest = blockstack.makeAuthRequest(
blockstack.generateAndStoreTransitKey(),
const authRequest = userSession.makeAuthRequest(
userSession.generateAndStoreTransitKey(),
'http://localhost:8080/',
'http://localhost:8080/manifest.json',
['store_write', 'publish_data'],
@ -245,12 +250,13 @@ import {
redirectToSignInWithAuthRequest
} from 'blockstack';
const authRequest = makeAuthRequest(undefined, undefined, undefined, undefined, undefined, undefined, {
var userSession = new UserSession()
const authRequest = userSession.makeAuthRequest(undefined, undefined, undefined, undefined, undefined, undefined, {
solicitGaiaHubUrl: true,
recommendedGaiaHubUrl: 'https://mygaiahub.com'
});
const authRequest = makeAuthRequest(
const authRequest = userSession.makeAuthRequest(
generateAndStoreTransitKey(),
'http://localhost:8080/',
'http://localhost:8080/manifest.json',
@ -262,7 +268,7 @@ const authRequest = makeAuthRequest(
}
);
redirectToSignInWithAuthRequest(authRequest);
userSession.redirectToSignInWithAuthRequest(authRequest);
```
Passing these parameters changes the storage hub URL prompt to the following:

332
overview_auth.md

@ -0,0 +1,332 @@
---
layout: learn
permalink: /:collection/:path.html
---
# Understand Blockstack authentication
{:.no_toc}
Blockstack Auth provides single sign on and authentication without third parties or remote servers. On this page, you'll get an overview of authentication from an developer and user perspective.
## User experience flow
Blockstack Auth is a bearer token-based authentication system. From an application user's perspective, Blockstack authentication is similar to legacy third-party authentication techniques that they're familiar with. Applications present users with a **Sign in with Blockstack** button.
![](images/signwithblockstack.png)
Assume a user, Alice, clicks the **Sign in with Blockstack** button on an app. She is
redirected to her copy of the Blockstack Browser. If the user has
signed into the DApp previously. The actual Blockstack sign-in dialog depends on
whether the user already has an existing session in the Blockstack Browser.
<img src="images/kingdom_notin.png" alt="">
Alice can choose to authenticate as one of her Blockstack IDs by selecting the
ID and clicking the **Approve** button. The Blockstack Browser shows Alice an approval dialog with information about your app including:
* The origin your app was served from
* Your app's name
* Your app's logo
* The types of permissions and data your app is requesting
Signing in with an identity is the means by which the user grants the DApp access. Access depends on the scope requested by the DApp. The default `store_write` scope allows the DApp to read the user profile and read/write user data for the DApp. Data is encrypted at a unique URL on a Gaia storage hub.
When she clicks approve, Alice is redirected back to the DApp where she is logged in.
## Application-authentication workflow
For an application developer, the application flow is different from the typical client-server flow used by centralized sign in services (e.g., OAuth). Rather, with Blockstack, the authentication flow happens entirely client-side.
A decentralized application (DApp) and the Blockstack Browser communicate during the authentication flow by passing back and forth two tokens. The requesting application sends the Blockstack Browser an `authRequest` token. Once a user approves a sign-in, the Blockstack Browser responds to the application with an `authResponse` token. These tokens are <a href="https://jwt.io/" target="\_blank">JSON Web Tokens</a>, and they are passed via URL query strings.
![](/storage/images/app-sign-in.png)
When a user chooses to **Sign in with Blockstack** on a DApp, calls the `redirectToSignIn()` method which sends the user to the Blockstack Browser. When Blockstack Browser is provided an ID, it generates an The browser responds with an authentication token and an _app private key_.
The app private key is application-specific. It is generated from the user's identity address private key using the `appDomain` as input. The key is ephemeral, it is generated for each execution of a key establishment process. This key is just used for the particular instance of the application, in this case to sign a sign-in request.
This app private key is also deterministic, meaning that for a given Blockstack ID and domain name, the same private key is generated each time. The app private key is securely shared with the app on each authentication and encrypted by the Blockstack Browser. The key serves three functions, it:
* is used to create the credentials that give an app access to the Gaia hub storage bucket for that specific app
* is used in the end-to-end encryption of files stored for the app on the user's Gaia hub
* serves as a cryptographic secret that apps can use to perform other cryptographic functions
A Blockstack Core node also generates a public key token which is sent to the
browser as an `authRequest` from the browser to the core node. The signed
authentication request is sent to Blockstack through a JSON Web Token (JWT).
Blocktack passes the token in via a URL query string in the `authRequest`
parameter:
`https://browser.blockstack.org/auth?authRequest=j902120cn829n1jnvoa...`
When the Blockstack node receives the `authRequest`, it generates a session token
and returns an authentication response (`authResponse`) to the application. Similar to the `authRequest`, the `authResponse` token includes a private key
intended only for the application. This allows the application to encrypt data
on user's personal Blockstack storage.
{% include note.html content="The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in <a href='https://github.com/blockstack/jsontokens-js'>Javascript</a> and <a href='https://github.com/blockstack/ruby-jwt-blockstack'>Ruby</a> available on the Blockstack Github to allow you to work with these tokens." %}
## Manifest file
Blockstack apps have a manifest file. This file is based on the [W3C web app manifest specification](https://w3c.github.io/manifest/). The following is an example manifest file.
```
{
"name": "Todo App",
"start_url": "http://blockstack-todos.appartisan.com",
"description": "A simple todo app build on blockstack",
"icons": [{
"src": "http://blockstack-todos.appartisan.com/logo.png",
"sizes": "400x400",
"type": "image/png"
}]
}
```
The Blockstack Browser retrieves the manifest file from the app during the
authentication process and displays some of the information in it such as the
app name and icon to the user. The location of the app manifest file is specific
in the authentication request token and **must** be on the same origin as the app
requesting authentication.
The manifest file **must** have [Cross-origin resource sharing (CORS) headers](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) that allow the manifest file to be fetched from any arbitrary source. This usually means returning a header like this:
```
Access-Control-Allow-Origin: *
```
How you implement cors depends in part on which platform/service you use to serve your application. For example, Netlify and Firebase have two different ways of configuring CORS. Consult your vendor documentation for more information.
## Key pairs
Blockstack Auth makes extensive use of public key cryptography. Blockstack uses ECDSA with the `secp256k1` curve. The following sections describe the various public-private key pairs used in the authentication process including:
* how they're generated,
* where they're used
* to whom the private key is disclosed.
{% include note.html content="The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in <a href='https://github.com/blockstack/jsontokens-js'>Javascript</a> and <a href='https://github.com/blockstack/ruby-jwt-blockstack'>Ruby</a> available on the Blockstack Github to allow you to work with these tokens." %}
### Transit private key
The transit private is an ephemeral key that is used to encrypt secrets that
need to be passed from the Blockstack Browser to the app during the
authentication process. It is randomly generated by the app at the beginning of
the authentication response.
The public key that corresponds to the transit private key is stored in a single
element array in the `public_keys` key of the authentication request token. The
Blockstack Browser encrypts secret data such as the app private key using this
public key and sends it back to the app when the user signs in to the app. The
transit private key signs the app authentication request.
### Blockstack ID Identity address private key
The identity address private key is derived from the user's keychain phrase and
is the private key of the Blockstack ID that the user chooses to use to sign in
to the app. It is a secret owned by the user and never leaves the user's
instance of the Blockstack Browser. This private key signs the authentication
response token for an app to indicate that the user approves sign in to that
app.
### App private key
The app private key is an app-specific private key that is generated from the
user's identity address private key using the `domain_name` as input. It is
deterministic in that for a given Blockstack ID and `domain_name`, the same
private key will be generated each time. The app private key is securely shared
with the app on each authentication, encrypted by the Blockstack Browser with
the transit public key.
## Scopes
Scopes define the information and permissions an app requests from the
user during authentication. Requested scopes may be any of the following:
| Scope | Definition|
|---|---|
| `store_write` | Read and write data to the user's Gaia hub in an app-specific storage bucket. |
| `publish_data` | Publish data so that other users of the app can discover and interact with the user. |
| `email` | Requests the user's email if available. |
If no `scopes` array is provided to the `redirectToSignIn` or `makeAuthRequest`
functions, the default is to request `['store_write']`.
## Authentication tokens
The app and the Blockstack Browser communicate during the authentication flow by
passing back and forth two tokens, the `authRequest` and the `authResponse`
token. The requesting application sends the Blockstack Browser an `authRequest`
token. Once a user approves a sign in, the Blockstack Browser responds to the
application with an `authResponse` token.
These tokens are [JSON Web Tokens](https://jwt.io/), and they are passed via URL
query strings.
### JSON Web Token signatures
Blockstack's authentication tokens are based on the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519)
with additional support for the `secp256k1` curve used by Bitcoin and many other
cryptocurrencies.
This signature algorithm is indicated by specifying `ES256K` in the token's
`alg` key, specifying that the JWT signature uses ECDSA with the secp256k1
curve. We provide both [JavaScript](https://github.com/blockstack/jsontokens-js)
and
[Ruby](https://github.com/blockstack/ruby-jwt-blockstack/tree/ruby-jwt-blockstack)
JWT libraries with support for this signing algorithm.
### Authentication request payload schema
``` JavaScript
const requestPayload = {
jti, // UUID
iat, // JWT creation time in seconds
exp, // JWT expiration time in seconds
iss, // legacy decentralized identifier generated from transit key
public_keys, // single entry array with public key of transit key
domain_name, // app origin
manifest_uri, // url to manifest file - must be hosted on app origin
redirect_uri, // url to which browser redirects user on auth approval - must be hosted on app origin
version, // version tuple
do_not_include_profile, // a boolean flag asking browser to send profile url instead of profile object
supports_hub_url, // a boolean flag indicating gaia hub support
scopes // an array of string values indicating scopes requested by the app
}
```
### Authentication response payload schema
```JavaScript
const responsePayload = {
jti, // UUID
iat, // JWT creation time in seconds
exp, // JWT expiration time in seconds
iss, // legacy decentralized identifier (string prefix + identity address) - this uniquely identifies the user
private_key, // encrypted private key payload
public_keys, // single entry array with public key
profile, // profile object or null if passed by profile_url
username, // blockstack id username (if any)
core_token, // encrypted core token payload
email, // email if email scope is requested & email available
profile_url, // url to signed profile token
hubUrl, // url pointing to user's gaia hub
version // version tuple
}
```
## `blockstack:` custom protocol handler
The `blockstack:` custom protocol handler is how Blockstack apps send their
authentication requests to the Blockstack Browser. When the Blockstack Browser
is installed on a user's computer, it registers itself as the handler for the
`blockstack:` customer protocol.
When an application calls
[`redirectToSignIn`](http://blockstack.github.io/blockstack.js/index.html#redirecttosignin)
or
[`redirectToSignInWithAuthRequest`](http://blockstack.github.io/blockstack.js/index.html#redirecttosigninwithauthrequest),
blockstack.js checks if a `blockstack:` protocol handler is installed and, if so,
redirects the user to `blockstack:<authRequestToken>`. This passes the
authentication request token from the app to the Blockstack Browser, which will
in turn validate the request and display an authentication dialog.
## Adding Blockstack Authentication to your app
The way you can add Blockstack Authentication to you app depends on whether your
app is a modern decentralized Blockstack App where code runs client-side without
trusted servers or a legacy client-server app where a server is trusted.
### Authentication in Client-side apps
This method is appropriate for decentralized client-side apps where the user's
zone of trust - the parts of the app that the user is trusting - begins and ends
with the code running on their own computer. In apps like these, any code the
app interacts with that's not on their own computer such as external servers
does not need to know who she is.
[Blockstack.js](https://github.com/blockstack/blockstack.js) provides API
methods that help you to implement Blockstack Authentication in your client-side
app.
#### Standard flow
The preferred way to implement authentication in these apps is to use the
standard flow. This flow hides much of the process behind a few easy function
calls and makes it very fast to get up and running.
In this process you'll use these four functions:
- [[redirectToSignIn]]
- [[isSignInPending]]
- [[handlePendingSignIn]]
- [[loadUserData]]
##### Starting the sign in process
When your app wants to start the sign in process, typically when the user clicks
a "Sign in with Blockstack" button, your app will call the [[redirectToSignIn]]
method of [blockstack.js](https://github.com/blockstack/blockstack.js).
This creates an ephemeral transit key, stores it in the web browser's
`localStorage`, uses it to create an authentication request token and finally
redirects the user to the Blockstack Browser to approve the sign in request.
##### Handling an authentication response
When a user approves a sign in request, the Blockstack Browser will return the signed authentication response token to the `redirectURI` specified in `redirectToSignIn`.
To check for the presence of this token, your app should call `isSignInPending`. If this returns `true`, the app should then call `handlePendingSignIn`. This decodes the token, returns the signed-in-user's data, and simultaneously storing it to `localStorage` so that it can be retrieved later with `loadUserData`.
```js
import * as blockstack from 'blockstack'
if (blockstack.UserSession.isSignInPending()) {
blockstack.UserSession.handlePendingSignIn()
.then(userData => {
const profile = userData.profile
})
}
```
#### Manual flow
Alternatively, you can manually generate your own transit private key and/or
authentication request token. This gives you more control over the experience.
For example, you could use the following code to generate an authentication
request on `https://alice.example.com` or `https://bob.example.com` for an app
running on origin `https://example.com`.
```js
const transitPrivateKey = generateAndStoreTransitKey()
const redirectURI = 'https://example.com/authLandingPage'
const manifestURI = 'https://example.com/manifest.json'
const scopes = ['scope_write', 'publish_data']
const appDomain = 'https://example.com'
const authRequest = makeAuthRequest(transitPrivateKey, redirectURI, manifestURI, scopes, appDomain)
redirectToSignInWithAuthRequest(authRequest)
```
### Authentication in client-server apps
*Note: Client-server authentication requires using a library written in the
language of your server app. There are private methods in blockstack.js that can
be accomplish this on node.js server apps, but they are not currently part of
our public, supported API.*
Using Blockstack Authentication in client-server apps is very similar to
client-side apps. You generate the authentication request using the same code in
the client as described above.
The main difference is that you need to verify the authentication response token
on the server after the user approves sign in to your app.
For an example of how verification can be done server side, take a look at the
[blockstack-ruby](https://github.com/blockstack/blockstack-ruby#to-verify-an-auth-response)
library.
Loading…
Cancel
Save