Lessons Learned: Steemconnect

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@r351574nc3·
0.000 HBD
Lessons Learned: Steemconnect
![](https://steemitimages.com/DQmfRUWMJ94gJSwkYDvLPewpnrZqxC92EXdVs2SHJ125ySa/image.png)

Firstly, this is not an OAuth2, authn, nor an authz tutorial. This is about what I learned about steemconnect. If any of this is confusing and/or you need more clarification, just reply and I will answer any questions. If anyone would like an OAuth2 explanation for steemconnect and how that all works, I can do that as well. 

# What is Steemconnect?

From the image above, and from the website, you can observe that steemconnect is a site that provides
* Additional tools to steemit users
    * A dashboard for tracking your wallet and account history
    * Management over your steem account including keys
* Tools for developers 
    * Oauth2 integration
    * Application registry and token management

As a regular user, it doesn't offer much more than your steem wallet.

As a developer, it does offer a couple things. Most importantly it offers authn/authz. It's not immediately apparent how it does this, so I'll explain.

## Oauth2

Normally, you think that when you login somewhere, you just give your username/password and that authenticates you. Your user is compared against some RBAC/ABAC identity management system and that functions as your authz. Steem complicates this a little bit with the introduction of keys. That and the fact that roles are already baked into Steem and Steemit. 

### Keys and Roles

There are 4 different keys and each one has a specific role attached to it.

#### Owner

> The owner key is the master key for the account and is required to change the other keys. The private key or password for the owner key should be kept offline as much as possible.

As far as I can tell, this has one purpose and that is account recovery. If your account is hijacked, you can use your owner key to recover it.

#### Active 

> The active key is used to make transfers and place orders in the internal market.

Just like it says, it's used for transfers. Basically, whatever action you take on your steem wallet requires your **active** key.


#### Posting

> The posting key is used for posting and voting. It should be different from the active and owner keys.

This is probably the one that is used the most because unless your dapp is a wallet-related dapp, it probably involves following, posting, voting, etc... which would require the posting key

#### Memo

> The memo key is used to create and read memos.

One of the most interesting but least used keys. It's the most interesting because this is what is actually used to secure messages and memos by encrypting/decrypting them.

#### How Roles are Used

Each role (Posting, Active, Owner, Memo) has a key. You simply use your key (WIF) appropriate for the task you are trying to accomplish. 

For example, using the [steem-js library](https://github.com/steemit/steem-js), I can create a post

```javascript
steem.broadcast.comment(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata, function(err, result) {
  console.log(err, result);
});
```

The `wif` would be my **posting** key. I cannot use another key for this task. This design provides two solutions
1. an identity management solution without having to write identity management software
1. public/private key security

It's pretty brilliant when you think about it, but it's flaw is actually the keys. They're obviously not intended for human consumption or use. They're intended for dapps. This is where steemconnect is helpful.

#### How Steemconnect Protects Keys with Oauth2

Steemconnect only really uses one key and that's your **posting** or **memo** key. *Uses* is probably not the right word since what is actually done with the key is it is verified against your account. Once you login and you prove that you are you, it does not store the key. 

```javascript
  const publicWif = role === 'memo' ? accounts[0].memo_key : accounts[0][role].key_auths[0][0];
  const code = encode(process.env.BROADCASTER_POSTING_WIF, publicWif, `#${token}`);
```

It pretty much just throws it away. Instead, steemconnect will issue something called a JWT (javascript web token).

#### Steemconnect and JWTs

Steemconnect abstracts its own roles. 
* **User** tokens are used on authentication and revoking tokens. It proves you're a user. User tokens don't persist. They expire almost immediately.
```javascript
/** Create a new access token for user */
const issueUserToken = user => (
  jwt.sign(
    { role: 'user', user },
    process.env.JWT_SECRET
  )
);
```
|Attribute|Description|
|------------|---------------|
|role|name of the role for this token|
|user|your username|

* **App** tokens give access to applications. App tokens expire in about a week. If you want a token that doesn't expire, use refresh tokens.
```javascript
const issueAppToken = (proxy, user, scope = []) => {
  const token = jwt.sign(
    { role: 'app', proxy, user, scope },
    process.env.JWT_SECRET,
    { expiresIn: config.token_expiration }
  );

  try {
    tokens.create({ client_id: proxy, user, token }).then(() => {
      debug(`A token for user @${user} with ${proxy} as proxy has been saved on database.`);
    });
  } catch (error) {
    throw new Error(error);
  }

  return token;
};
```
|Attribute|Description|
|------------|---------------|
|role|name of the role for this token|
|user|your username|
|proxy|client id of the application. It is referred to as a proxy because the application proxies your account.|
* **Code** tokens are verification codes used prior to issue app/refresh tokens. Like **User** tokens, this also expires almost immediately.
```javascript
const issueAppCode = (proxy, user, scope = []) => (
  jwt.sign(
    { role: 'code', proxy, user, scope },
    process.env.JWT_SECRET,
    { expiresIn: 600 }
  )
);
```
|Attribute|Description|
|------------|---------------|
|role|name of the role for this token|
|user|your username|
|proxy|client id of the application. It is referred to as a proxy because the application proxies your account.|
|scope|is described in this steemconnect documentation on [scopes](https://github.com/steemit/steemconnect/wiki/OAuth-2#scopes)|

* **Refresh** refresh tokens are tokens that never expire. These need to be protected because they're actually used to derive **App** tokens. If you discover your refresh token has been compromised, you should revoke your token immediately.
```javascript
const issueAppRefreshToken = (proxy, user, scope = []) => (
  jwt.sign(
    { role: 'refresh', proxy, user, scope },
    process.env.JWT_SECRET
  )
);
```
|Attribute|Description|
|------------|---------------|
|role|name of the role for this token|
|user|your username|
|proxy|client id of the application. It is referred to as a proxy because the application proxies your account.|
|scope|is described in this steemconnect documentation on [scopes](https://github.com/steemit/steemconnect/wiki/OAuth-2#scopes)|
> Refresh tokens are issued when the `offline` scope is specified upon token request. 
```javascript
  if (req.scope.includes('offline')) {
    payload.refresh_token = issueAppRefreshToken(req.proxy, req.user, req.scope);
  }
  res.json(payload);
```

## Proxies

To recap, rather than use our keys directly for authentication, we now use tokens. By logging in with a memo or posting key to prove we own the account, steemconnect will give us a token that lasts for a week and will allow us all the access we need.

### How does steemconnect gain access?

This is an important question. We only gave a posting key and/or memo key. How in the world did steemconnect turn that into access to everything else? The answer is in `user_metadata`. Steemconnect modifies your authorizations on your account through your `account_metadata`. Here's how:

```javascript
{
    account: "r351574nc3", 
    owner: {	
        weight_threshold:	1,
        account_auths:	[[]],
        key_auths:[["STM867Vr1jWj8r1mfzJnJcjfpyyugrgK3vgX6ogHCMQaFvUtYfnEe", 1]],
    },
    active: {
        weight_threshold:	1,
        account_auths:	[[]],
        key_auths: [["STM5ZSjdsBNQ8BHBSLcVJP7CdkybUauYh4aL3yAvri9Bntr2PeL3o", 1]]
    },
    posting: {
        weight_threshold:	1,
        account_auths: [["sylveon", 1]],
        key_auths: [["STM5qFtsnMAkB5p9cEiXptde2DCgPDnP29zhtvWyqDdfBjKpTzyBX", 1]]
    },
    memo_key:	STM6Vpnv9FmP7PtDDBVznaab1e1xdASETGGAkGWSx8N2pDoX1GU7b,
    json_metadata:	{}
}
```

The above is a sample `account_metadata` object with the key definitions of an application, `sylveon`, created with steemconnect. Once you login with steemconnect and a token is granted, account authorizations are granted to the application. Consent for these is given when you login. 

![](https://steemitimages.com/DQmQF75YNZUsaMDuZaXT5ncFcU7dKxsmByk2FQFDxGs3WF7/image.png)

Once you content to access to those scopes, an `account_auth` is added for the application to the appropriate role. 

For me, I consented to `sylveon` having access to my posting role:
```javascript
   posting: {
        weight_threshold:	1,
        account_auths: [["sylveon", 1]],
        key_auths: [["STM5qFtsnMAkB5p9cEiXptde2DCgPDnP29zhtvWyqDdfBjKpTzyBX", 1]]
    }
```

### The Dapp is the Proxy

The important reason for why you give access to the application is because the application impersonates you or rather, it acts as your proxy. What is happening is I am giving permission for `sylveon` to post as me. 

Let's use a couple other examples. 
* Busy
* Dtube
* DLive


The above are all dapps that are given access to post as you.

# Accounts/Apps Created with Steemconnect

One of the features Steemconnect offers to developers is an app store and app registry. Developers can create applications of their own. Creating an application means likewise creating an account. This requires 3.0 STEEM to do.

## Accounts are yours but not yours

Accounts created with steemconnect automatically are given steemconnect `account_auth`.

```javascript
{
    account: "sylveon", 
    owner: {	
        weight_threshold:	1,
        account_auths: [["steemconnect", 1]],
        key_auths:[["STM867Vr1jWj8r1mfzJnJcjfpyyugrgK3vgX6ogHCMQaFvUtYfnEe", 1]],
    },
    active: {
        weight_threshold:	1,
        account_auths: [["steemconnect", 1]],
        key_auths: [["STM5ZSjdsBNQ8BHBSLcVJP7CdkybUauYh4aL3yAvri9Bntr2PeL3o", 1]]
    },
    posting: {
        weight_threshold:	1,
        account_auths: [["steemconnect", 1]],
        key_auths: [["STM5qFtsnMAkB5p9cEiXptde2DCgPDnP29zhtvWyqDdfBjKpTzyBX", 1]]
    },
    memo_key:	STM6Vpnv9FmP7PtDDBVznaab1e1xdASETGGAkGWSx8N2pDoX1GU7b,
    json_metadata:	{}
}
```

The private key are not saved/stored or given back to you. Instead, steemconnect gives itself complete authorization over your app, but not you. This is important to realize that you basically lose your account by purchasing through steemconnect.

All is not lost, steemconnect is OSS and you can basically fork the project and reimplement the features automatically adding yourself with steemconnect to the account. In another post, I will show how to do this as well as other steemconnect hacks.
👍 , , , , , , , , , , , , , , , , , , , , , , , ,