# HAS Wrapper library

The hive-auth-wrapper library relieves you from managing a WebSocket connection and the events it generates. It allows you to use the functionality of the HAS infrastructure in the same way as you would with a traditional API.

The source code is open-source and available on [Github](https://github.com/hiveauth/hive-auth-wrapper).

### Installation

`npm install hive-auth-wrapper`

### Usage

```javascript
import HAS from 'hive-auth-wrapper'

// Your application information
const APP_META = {name:"myapp", description:"My HAS compatible application", icon:undefined}

// Create an authentication object
const auth = {
  username: "username"  // required - replace "username" with your Hive account name (without the @)
  expire: undefined
  key: undefined
}

// Retrieving connection status
const status = HAS.status()
console.log(status)
```

### **Configuration**

The HAS wrapper should work with its default configuration. However, you can change it by calling `setOptions(options)`. The `options` object has the following structure:

```javascript
{
  host: string = undefined,
  auth_key_secret: string = undefined
}
```

{% tabs %}
{% tab title="Properties" %}

* **`host`**: *(optional)* HAS server to connect to (default to wss\://hive-auth.arcange.eu)
* **`auth_key_secret`**: *(optional)* the PKSA pre-shared encryption key to use to encrypt any `auth_key` passed with an `auth_req` payload.
  {% endtab %}
  {% endtabs %}

{% hint style="danger" %}
`auth_key_secret` should be defined only if you are running your own PKSA in service mode and the app sends the auth\_key online with the auth\_req payload!
{% endhint %}

### **Authentication**

When the app performs its first authentication, it uses an `auth` object without `expire` property. The `auth.expire` will be updated if the authentication succeeds.

If the app already owns an `auth` object which has not expired, it may be reused without calling `authenticate()` again.

When authenticating a user, the app can optionally request the PKSA to sign a challenge using one of the posting, active or memo keys.

```javascript
if(auth.expire > Date.now()) {
    // previous authentication is still valid - no need to log in again
    resolve(true)
} else {
    let challenge_data = undefined
    // optional - create a challenge to sign with the posting key
    challenge_data = {
        key_type: "posting",
        challenge: JSON.stringify({
            login: auth.username,
            ts: Date.now(),
        })
    }

    HAS.authenticate(auth, APP_META, challenge_data, (evt) => {
        console.log(evt)    // process auth_wait message
    }))
    .then(res => resolve(res))  // Authentication request approved
    .catch(err => reject(err))  // Authentication request rejected or error occured
}
```

### **Broadcasting transactions**

The APP can request the PKSA to sign and/or broadcast a transaction.

```javascript
const op = [ 
    "vote", 
    { 
        voter: auth.username, 
        author: "author", 
        permlink: "permlink", 
        weight: 10000 
    } 
]

HAS.broadcast(auth, "posting", [op], (evt)=> {
    console.log(evt)    // process sign_wait message
}) )
.then(res => resolve(res) ) // transaction approved and successfully broadcasted
.catch(err => reject(err) ) // transaction rejected or failed 
```

### Signing a challenge

Apps may want to validate an account by asking it to sign a predefined text string (challenge) with one of its keys.

```javascript
try {
     const challenge_data = {
        key_type: "posting",
        challenge: JSON.stringify({
            login: auth.username,
            ts: Date.now(),
        })
    }
    const res = await HAS.challenge(auth, challenge_data)
    
    // Validate signature against account public key
    const sig = ecc.Signature.fromHex(resC.data.challenge)
    const buf = ecc.hash.sha256(challenge, null, 0)
    const verified = sig.verifyHash(buf, ecc.PublicKey.fromString(resC.data.pubkey));
    
    if(verified) {
        console.log("challenge succeeded")
    } else {
        console.error("challenge failed")
    }
} catch(e) {
    console.error("challenge failed")
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hiveauth.com/tutorials/app-code-example/has-wrapper-library.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
