# Overview

The TOZ Platform has evolved over a decade of collaboration with renowned institutions such as DARPA, NIST, EPRI, and the NIH, enabling it to offer an all-encompassing solution for fostering trust among people and organizations. Its Software-as-a-Service (SaaS) model, delivered through user-friendly APIs and SDKs, streamlines the development of trustworthy digital products and connected devices.

## Why TOZ is Different

### Building digital trust into products and connected devices

The fundamental pillars of cybersecurity are identity, access, and encryption. Many cybersecurity technologies are flawed due to the lack of consistent application of encryption, and its separate management from identity. TOZ resolves this issue by offering a purely cryptographic strategy for controlling access.

The cornerstone of this framework is identicryption (IDEC), an innovative amalgamation of identity-based encryption and end-to-end encryption methodologies. IDEC is expertly designed in conjunction with advanced identity management, decentralized tokens, and request brokering to fulfill the architectural requirements.

When implemented, IDEC facilitates the coordination of identity management, privileged access management, and secure storage functions, functioning harmoniously as a unified system.

Through SDKs, APIs and federation, the TOZ Platform integrates into existing IT infrastructure to bring the benefits of IDEC to any product, service, or enterprise.

## TOZ ID

### Identity is everything so everything has an identity

[TOZ ID](https://tozny.com/tozid) provides identity management for people, apps, services, and devices. TOZ ID provides IdP and Single Sign-On (SSO) functionality and can be federated to IdP services like Azure Active Directory (AAD) or Okta. TOZ ID provides a secure foundation for integrating identity into all aspects of data and access management.

Protecting identity is paramount for building trust. TOZ ID supports a wide variety of MFA schemes and can support custom authentication schemes of all types. Supporting TOZ ID are TOZ Auth and TOZ Token which extend the reach of TOZ ID and reduce friction during user authentication.

## TOZ PAM

### Cryptographic role based access control

At the heart of the TOZ Platform is priviledged access management (PAM) functionality to manage access and privileges completely cryptographically. This cryptographic approach to access management is the backbone to building new trust relationships between individuals and organizations. TOZ PAM enables fine grain control of data access while also supporting sophisticated policies for limiting access. For example, access can be limited to time periods or defined number of uses as well as requiring additional approval at time of access.

## TOZ Store

### Flexibly store heterogeneously encrypted data

[TOZ Store](/toz-store/getting-started#overview) provides a convenient method for managing the datastores where encrypted data rests.

## Software Development Kits

Identity management and end-to-end encryption can be fully integrated into **your** product thanks to our robust SDKs. We support a variety of languages and platforms including web front-end, Android, iOS, and server-side back-end. Please see the [SDK documentation for details](https://docs.tozny.com/) or visit our [Github](https://github.com/tozny/).

## Learn More and Contact Us

Please visit [tozny.com](https://tozny.com/) for more information, or feel free to [contact us](https://tozny.com/contact/) to discuss your needs with our team. You can also learn more about IDEC in our new [white paper](https://toznystage.wpengine.com/wp-content/uploads/2023/05/TOZ-White-Paper-Building-trust-through-digital-products-and-connected-devices-with-an-identity-and-encryption-first-architecture.pdf/).


# Why Encrypt?

### Encryption Saves Money

Here’s a table from the [excellent Ponemon Institute report on the cost of data breaches](http://www-03.ibm.com/security/infographics/data-breach/). It shows the per-user cost of a data breach across various industries. For instance, a 1,000 user data breach would cost an average of $141,000 to remediate. In healthcare, the figure is more than double that. The most effective **technical** means for reducing the cost of a data breach is encryption.

### Encryption & Compliance

Any organization that handles the data of EU citizens is likely familiar with the EU General Data Privacy Regulation (GDPR). GDPR has a massive impact because it has very strict enforcement penalties.\\

Organizations in breach of GDPR [can be fined up to 4% of annual global turnover](http://www.eugdpr.org/key-changes.html) or €20 Million (whichever is greater). For security breaches, the fine is half of that, but would not apply if the data is encrypted when it’s breached. The EU also holds an expansive view of what is considered “personal data”, including name, IP address, and email address, which appear in most user databases.\\

US companies often think this doesn’t apply to them, but, [the rules follow the data](https://www.hanzo.co/blog/what-us-companies-need-to-know-about-the-gdpr):

> “...this applies to US companies that are not located in the EU but do offer goods or services to EU citizens or monitor the behaviors of EU citizens. These companies must be in compliance with GDPR rules on the data privacy of these individuals.”\\

From a development standpoint, even if the vast majority of your users are not EU citizens, encryption is still required if you want to continue processing any EU citizen data. US companies can implement “[Privacy Shield](https://www.privacyshield.gov/article?id=OVERVIEW)” to demonstrate to the EU that they are compliant.\\

Similarly in the US healthcare system, [the HIPAA privacy rule requires health information to be encrypted](https://www.hhs.gov/hipaa/for-professionals/breach-notification/guidance/index.html):

> “Electronic PHI has been encrypted as specified in the HIPAA Security Rule by “the use of an algorithmic process to transform data into a form in which there is a low probability of assigning meaning without use of a confidential process or key” (45 CFR 164.304 definition of encryption) and such confidential process or key that might enable decryption has not been breached. To avoid a breach of the confidential process or key, these decryption tools should be stored on a device or at a location separate from the data they are used to encrypt or decrypt.”


# Quickstart

These quick start steps will get you up and running with an integration to your business critical applications for enterprise SSO.

## Open a TOZ Account

Register for a free developer sandbox and start experimenting with our platform.

[Create Your Free Account](https://dashboard.tozny.com/register)

## Create Your Realm

A realm represents your organization and provides the base URL for your API requests and redirects. For example if your organization is called Acme, a good realm name would be acme.

{% hint style="warning" %}
Realm names should be lower case and only contain letters. The easier they are to remember the better the experience will be for your users.
{% endhint %}

In the dashboard follow these steps:

1. Navigate to TOZ ID on the left menu
2. Select "Realms"
3. Select "Create Realm" and give it a name
4. Select "Manage Realm" to login and administer your realm

## Create a Client Application

A client application is any relying party that interfaces with TOZ ID. Common clients include GSuite, Slack, and Jira. We've got preconfigured quick setup for those and others in the setup screen on the TOZ ID Adminstration page. If you need help configuring a client reach out to us anytime at <support@tozny.com> or checkout the in-depth tutorials on the menu to your left.


# Authentication Overview

Authentication in TozID is handled differently than most traditional identity management platforms.  Here we'll look at what makes TozID different.

## Traditional Authentication

To understand how TozID is different its important to understand how traditional authentication ocurs. In most identity platforms a user sets a username and password and that information is transferred to a server and then encrypted and stored. When a subsequent login is attempted the credentials you enter are transmitted to the server, encrypted and compared against the stored value. If they match you're allowed in and if not you're denied access.

## TozID Authentication

In TozID the credentials you enter in your mobile device or browser are never transmitted in plain text. We derive a set of encryption keys using [PBKDF](https://en.wikipedia.org/wiki/PBKDF2) (Password Based Key Derivation Function) and sign a request to TozID to look up credentials. If your public key is found we return a set of encrypted credentials and your derived keys are used to decrypt the returned payload and then be able to issue a subsequent request for JWT.

## Compatbility

TozID retains compatibility with all standard SAML, OAuth, and OpenID Connect workflows. We provide quick integrations through our catalogue of applications and you can be up and running in minutes. Additionally TozID continues to protect your users credentials with end-to-end encryption in that sign in process with cryptography all the way to the edges of your infrastructure.


# Enterprise SSO


# Adding Users

## Creating New Users

To create new users in TozID you'll first want to login to your realm from the Tozny dashboard. Once there navigate to the users section from the left menu and select "Add User" on the top right of your screen.

![Add User Screen from TozID](/files/-M-X9rPKBAgn7ptdC5Zk)

| Field              | Description                                                                                                                                                                                                                        |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Email              | A required field that gives your user their unique login name.                                                                                                                                                                     |
| Registration Token | A required field that associates which Tozny registration token should be linked to the user. Rarely should this field be modified but you can create additional registration tokens from the Tozny Dashboard.                     |
| Broker URL         | This field is where users will be directed to when recovering their credentials. Because Tozny uses end-to-end encryption we require explicit permission from you to allow for password resets. This field should not be modified. |
|                    |                                                                                                                                                                                                                                    |

###


# Slack (Quick Setup)

How to quickly configure Slack for TozID SSO for your workplace or organization.

## What You'll Need

* Your Tozny account - [create one free here](https://dashboard.tozny.com/register)
* Admin access to your Slack team configuration and a Slack Plus subscription or better
* About 15 minutes of time

## Configure TozID for Slack SSO

Create a new client application by logging into your TozID realm, selecting clients from the left menu, and clicking "create" on the top right. Select Slack from the drop down menu as shown in the screenshot below.

![Slack Configuration](/files/-M-lNrhjOkFFohohpZs0)

{% hint style="info" %}
Your Slack domain is simply your organization name assigned by slack. So if you sign in at acme.slack.com your site domain is "<https://acme.slack.com>"
{% endhint %}

## Configure Slack

Navigate to your organization authentication settings and enable SAML Single Sign-On. To find this setting go to your Slack admin page, select Authentication from the left menu, and select the "SAML Authentication Settings" menu button. Below is a table of the configuration settings and the corresponding values as well as a screenshot of the completed settings.

| Setting                      | Value                                                                    |
| ---------------------------- | ------------------------------------------------------------------------ |
| SAML 2.0 Endpoint            | <https://id.tozny.com/auth/realms/\\><realm>/protocol/saml/clients/slack |
| Identity Provider Issuer     | <https://id.tozny.com/auth/realms/\\><realm>                             |
| Public Certificate           | Paste your certificate                                                   |
| Update profile on login      | Checked                                                                  |
| Allow users to change email  | Unchecked                                                                |
| Advanced - Sign AuthnRequest | Unchecked                                                                |
| Service Provider             | <https://slack.com>                                                      |
| Responses Signed             | Checked                                                                  |
| Assertions Signed            | Checked                                                                  |

![Basic Settings for TozID SAML with Slack](/files/-M-lP9SWPyLZoBDQBxNM)

![Advanced Settings for TozID SAML with Slack](/files/-M-lPEPKnZuksGe1l2Wr)


# Freshdesk (Quick Setup)

This describes the steps necessary to complete the Freshdesk integration when using the rapid setup guide in TozID.

## What You'll Need

* Your Tozny account - [create one free here](https://dashboard.tozny.com/register)
* Admin access to your Freshdesk account
* About 15 minutes to complete the setup

## Configure TozID

Create a new client application in TozID by logging into your realm, navigating to clients, and selecting "create".

![Create Freshdesk Client Screen](/files/dEqRU4iB3iCXzG0LCG7j)

Enter the following values and select save.

| Field        | Value                                                                    |
| ------------ | ------------------------------------------------------------------------ |
| Client ID    | Any unique string to identify this client. Example: fresh-desk           |
| Base URL     | Freshdesk Login URL. Example: <https://myaccount.myfreshworks.com/login> |
| Redirect URL | Copy from Freshdesk configuration                                        |

![Freshdesk Redirect URL Screen](/files/BzrooDbBnZk8nBBDTmdb)

## Configure Freshdesk

Login to your Freshdesk admin account. Select "security from the left menu. Click on “Default Login Method”.

Enable “SSO Login” and edit “SSO with OIDC” if it is already present under “Configured SSOs”.

![Freshdesk Enable SSO Screen](/files/3EPdEqsyVcHK6VmAqcGu)

If there is no “SSO with OIDC” under “Configured SSOs” then add a new one.

![Freshdesk Add SSO](/files/CuRUtnWMbfNlvlgpRmZJ)

Click “+ Add another SSO” and choose “IdP of your choice” – “OIDC”.

![IdP of your Choice Screen](/files/OosLcgkvaiJ5xa21e2M8)

Configure the following values(Create Freshdesk client in TozID and edit it to get the below values):

| Field             | Value                                               |
| ----------------- | --------------------------------------------------- |
| Client Id         | Client Id from TozID Client Settings Tab            |
| Client secret     | Secret from TozID Client Credentials Tab            |
| Authorization URL | Authorization URL from TozID Client Credentials Tab |
| Access token URL  | Access token URL from TozID Client Credentials Tab. |

![Example Freshdesk Configuration](/files/BFt5NbX1hz6Tik7WzhJy)

![TozID Client ID](/files/ZWLdjTsETqicV3MHDbLn)

![TozID Credentials](/files/bXVUYcq3TB2J5hp7YnUA)

## Freshdesk's Login Button

Click Advanced Options and Add Button Label as "Login with TozID".

![Freshdesk SSO Login Button](/files/V2hwnaKZ9GeVaIos4Qwk)

## Wrapping Up

Select save and ensure your users are correctly configured in TozID. The same users should also be inside Freshdesk. Once completed, you should be able to sign into Freshdesk agent portal with TozID. Having issues? Reach us at <support@tozny.com>


# Atlassian (Quick Setup)

This describes the steps necessary to complete the Atlassian (Jira) integration when using the rapid setup guide in TozID.

## What You'll Need

* Your Tozny account - [create one free here](https://dashboard.tozny.com/register)
* Admin access to your Atlassian account
* About 15 minutes to complete the setup

## Configure TozID

Create a new client application in TozID by logging into your realm, navigating to clients, and selecting "create".

![Create Atlassian Client Screen](/files/-M-k6qjEijVuTQXQoVoB)

{% hint style="info" %}
Your entity ID can be found at <https://admin.atlassian.com> and then navigating to your organization, security, then SAML Single Sign-On. It will be a series of letters and numbers similar to the example in the screenshot above.
{% endhint %}

Enter your entity ID and select save.

## Configure Atlassian

Navigate to your Atlassian administration page. Select "security" and then "SAML single sign-on" from the left menu. Configure the following values:

| Field                       | Value                                                                   |
| --------------------------- | ----------------------------------------------------------------------- |
| Identity provider Entity ID | <https://id.tozny.com/auth/realms/\\><your realm name>                  |
| Identity provider SSO URL   | <https://id.tozny.com/auth/realms/\\><realm>/protocol/saml/clients/jira |
| Public x509 certificate     | \<your cert data>                                                       |

![Example Atlassian Configuration](/files/-M-k9tplrF1YerKALFtQ)

## Wrapping Up

Select save and be sure your users are correctly configured in TozID. Once completed you should be able to sign into Atlassian products with TozID. Having issues? Reach us at <support@tozny.com>


# Dropbox (Quick Setup)

This describes the steps necessary to complete the Dropbox integration when using the rapid setup guide in TozID.

## What You'll Need

* Your Tozny account - [create one free here](https://dashboard.tozny.com/register)
* Admin access to your Dropbox Business account
* About 15 minutes to complete the setup

## Configure TozID

Create a new client application in TozID by logging into your realm, navigating to clients, and selecting "create".

![Create Dropbox Client Screen](/files/NTmLblEVVhQzalUjFwzI)

Enter the following values and select save.

| Field    | Value                  |
| -------- | ---------------------- |
| Base URL | Dropbox SSO Login URL. |

![Dropbox Redirect URL Screen](/files/now1UoCVSlkkOv8QzJg9)

## Configure Dropbox

Login to your Dropbox Business Advanced admin account. Click "Admin Console" then "Settings" from the left menu. Scroll down to find "Single sign-on" and click it.

Enable “Single Sign-on”.

![Dropbox Enable SSO Screen](/files/EYuqrDzxbYrRYBJBcoNw)

Configure the following values in Dropbox:

| Field             | Value                                                                                   |
| ----------------- | --------------------------------------------------------------------------------------- |
| IdP Sign-in URL   | TozID SAML Sign-in URL: <https://id.tozny.com/auth/realms/\\><realm-name>/protocol/saml |
| X.509 Certificate | X.509 Certificate from TozID                                                            |

![Dropbox Configuration](/files/HvPB108XteGAreWGNt6x)

Go to "Realm Settings" and click "SAML 2.0 Identity Provider Metadata"

![Get TozID X.509 Certificate](/files/w510r6p9sQPZrNugNouB)

Copy X.509 Certificate value and paste it in a new .pem file(Create a file with .pem extension).

![TozID X.509 Certificate](/files/tnudn97fe2wNeifeZ1Bj)

Dropbox requires X.509 certificate in .pem file, so create a new file with ".pem" extension and paste the certificate value in the below format.

```
-----BEGIN CERTIFICATE-----

<X.509 Certificate>

-----END CERTIFICATE-----
```

![TozID X.509 Certificate File](/files/UBFFnEoKngqt2KPI4C55)

Upload this newly created certificate file in dropbox.

## Wrapping Up

Select save and ensure your users are correctly configured in TozID. Same users should also be inside Dropbox(Team Members). Once completed, you should be able to sign in to Dropbox Teams account with TozID. Having issues? Reach us at <support@tozny.com>


# GSuite

How to configure Google as a relying party manually for TozID or Keycloak

## Overview

Following this tutorial will show you how to complete the integration between TozID and GSuite. This will allow your organization to sign into all of their Google products using TozID. Additionally these configuration settings can be useful in any Keycloak based deployment. Note that with TozID your passwords never leave the client devices to add another layer of protection. Learn more at [TozID](https://tozny.com/tozid).

{% hint style="info" %}
TozID allows for instant configuration of GSuite. Simply select "Google SAML" from the drop down menu when creating a client.
{% endhint %}

## Prerequisites

* Admin access to GSuite
* Admin access to your TozID Realm
* 30 minutes

## TozID Configuration

Start by logging into your realm through the Tozny dashboard. Select **clients** from the left hand menu and then the **create** button on the top right. Enter the following values:

* **Client ID:** google.com/a/\<your\_gsuite\_domain> (eg google.com/a/tozny.com)
* **Client Protocol:** saml
* **Client SAML Endpoint:** empty

![Client creation step](/files/-LwPMmdQUBZm2WDk9JpU)

Once you've created the client application we can configure the details of our SAML integration. Below are the settings:

| Setting                                     | Value                                                                              |
| ------------------------------------------- | ---------------------------------------------------------------------------------- |
| Client ID                                   | google.com/a/\<your\_gsuite\_domain>                                               |
| Name                                        | Google                                                                             |
| Enabled                                     | ON                                                                                 |
| Client Protocol                             | SAML                                                                               |
| Include AuthnStatement                      | ON                                                                                 |
| Sign Documents                              | ON                                                                                 |
| Sign Assertions                             | ON                                                                                 |
| Signature Algorithm                         | RSA\_SHA256                                                                        |
| SAML Signature Key Name                     | None                                                                               |
| Canonicalization Method                     | Exclusive                                                                          |
| Force POST Binding                          | ON                                                                                 |
| Front Channel Logout                        | ON                                                                                 |
| Force Name ID Format                        | ON                                                                                 |
| Name ID Format                              | email                                                                              |
| Base URL                                    | /auth/realms/\<your\_realm\_name>/protocol/saml/clients/googleapps?RelayState=true |
| IDP Initiated SSO URL Name                  | googleapps                                                                         |
| IDP Initiated SSO Relay State               | True                                                                               |
| Assertion Consumer Service POST Binding URL | <https://www.google.com/a/\\>\<your\_gsuite\_domain>/acs                           |

![](/files/-M1ak8hcxYh9djaCf3PN)

Configure the mapper which maps an email address to the SAML attribute of emailAddress. Navigate to the mappers tab of the client.

![Gsuite Mapper Configuration](/files/-LwPQREpLuDjOf5S0wQQ)

Extract your X509 certificate for upload to Google. To do this navigate to the Installation tab of the client application and select **SAML Metadata IDPSSODescriptor** from the drop down. You need to select only the text between the tag **\<dsig:X509Certificate>**. Save that to a new text file called cert.pem.

## GSuite Configuration

Navigate to the GSuite Admin portal. Once logged in go to the **security** section of the portal.

![](/files/-LwPSZWM9vcxVaGt2cjy)

Expand the section labeled **Set up single sign-on (SSO)** and enter the following values with your realm where applicable.

| Setting                                      | Value                                                                                      |
| -------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Setup SSO with third party identity provider | CHECKED                                                                                    |
| Sign-in Page URL                             | <https://api.e3db.com/auth/realms/\\>\<your\_realm\_name>/protocol/saml/clients/googleapps |
| Sign-out Page URL                            | <https://id.tozny.com/\\>\<your\_realm\_name>                                              |
| Change Password URL                          | <https://id.tozny.com/\\>\<your\_realm\_name>                                              |
| Verification Certificate                     | Upload your cert.pem file                                                                  |
| User a domain specific issuer                | CHECKED                                                                                    |

![Gsuite configuration](/files/-LwPSdmPnJZrpE9J6eiT)

You're all set! Save those settings and when you navigate to your gsuite gmail domain you'll be able to login with your TozID account.


# Office 365

This describes the steps necessary to complete the Office 365 integration when using the rapid setup guide in TozID.

## What You'll Need

* Your Tozny account - [create one free here](https://dashboard.tozny.com/register)
* Admin access to your Office 365 account
* Custom domain to use for Office 365
* About 15 minutes to complete the setup

## Configure TozID

Create a new client application in TozID by logging into your realm, navigating to clients, select "create" and choose "Office 365".

![Create Office 365 Client Screen](/files/nvLyPrmhCfUa0ZZTr41y)

## Configure Office 365

Login to your Office 365 admin account(<https://admin.microsoft.com/>). Click "Settings" then "Domains" from the left menu. Click on "Add Domain" and follow the steps to verify it's ownership.

![Add domain in Office 365 Admin](/files/g4Wg5cAeB5PlZ7zkaBGS)

Once domain verification is completed and the domain added, then follow below steps.

### Step 1: Federate your Office 365 custom domain through PowerShell.

To run script,

1. Install MSOnline Module. Run "Install-Module MSOnline" command
2. Import MSOnline Module. Run "Import-Module MSOnline" command
3. Connect Office 365 account. Run "Connect-MsolService" command, it will open login screen for Office 365 account.
4. Run below script.

Configure the following values in powershell script:

| Field                           | Value                                                                   |
| ------------------------------- | ----------------------------------------------------------------------- |
| DomainName                      | Domain name which is added at Office 365 admin.                         |
| FederationBrandName             | Any Name Example: "MS Office SAML".                                     |
| Authentication                  | Static value "Federated".                                               |
| PassiveLogOnUri                 | <https://staging.id.tozny.com/auth/realms/\\><realm-name>/protocol/saml |
| ActiveLogOnUri                  | <https://staging.id.tozny.com/auth/realms/\\><realm-name>/protocol/saml |
| SigningCertificate              | X.509 Certificate                                                       |
| IssuerUri                       | <https://staging.id.tozny.com/auth/realms/\\><realm-name>               |
| LogOffUri                       | <https://staging.id.tozny.com/auth/realms/\\><realm-name>/protocol/saml |
| PreferredAuthenticationProtocol | Static value "SAMLP".                                                   |

Replace placeholders(\<field-name>) with values in below powershell script and run it.

```
  Set-MsolDomainAuthentication `
  -DomainName \<domain-name> `
  -FederationBrandName \<federation-brand-name> `
  -Authentication Federated `
  -PassiveLogOnUri \<passive-log-on-uri>  `
  -ActiveLogOnUri \<active-log-on-uri>  `
  -SigningCertificate \<signing-certificate> `
  -IssuerUri \<issuer-uri> `
  -LogOffUri \<log-off-uri> `
  -PreferredAuthenticationProtocol "SAMLP"
```

Get Signing Certificate from your Realm Settings.

![TozID X.509 Certificate File](/files/w510r6p9sQPZrNugNouB)

![TozID X.509 Certificate File](/files/tnudn97fe2wNeifeZ1Bj)

### Step 2: Add Office 365 users through PowerShell (User email address should be of federated domain)

| Field             | Value                                                        |
| ----------------- | ------------------------------------------------------------ |
| UserPrincipalName | Email address of the user. Should be of federated domain.    |
| ImmutableId       | Immutable Id from Office 365 created inside your realm user. |
| DisplayName       | Fullname of the user.                                        |
| FirstName         | Firstname of the user.                                       |
| LastName          | Lastname of the user.                                        |

```
New-MsolUser `
-UserPrincipalName <email-address> ` 
-ImmutableId <immutable-id> `
-DisplayName "<full-name>" `
-FirstName <first-name> `
-LastName <last-name> `
```

#### ImmutableId

Immutable Id's are unique ID for the user which will be auto created inside your realm user attribute when they try to login before the user is being created. Go to office 365 login in incognito window and put user email address in login screen, it will redirect to "TozID" login page. That's it. ImmutableId will be created for that user inside User Attribute with the key "saml.persistent.name.id.for.urn:federation:MicrosoftOnline".

### Step 3: Login to Office 365 admin account and assign licenses to apps for the created users.

![Office 365 Assign Licenses](/files/oXoGn7h9sfTl8zAZpO0V)

## Wrapping Up

Select save and ensure your users are correctly configured in TozID and in Office 365. Once completed, users should be able to sign in to Office 365 account with TozID. Having issues? Reach us at <support@tozny.com>


# Customer Identity Management


# Vue with TozID

## Introduction

In this guide we'll show you how use both TozID and TozStore to securely authenticate and store data using end to end encryption in a Vue based application. We'll keep things simple and use the Vue CLI to bootstrap our application and only use the Tozny SDK as our other dependency. Once we're done this application will let you do the following:\
\
1\. Secure login with zero knowledge authentication powered by TozID\
2\. End to end encrypted reads and writes using TozStore\
\
This tutorial assumes you have some basic knowledge of Vue but we'll walk through all of the steps. As always the complete source code is linked below.

### Project Initialization

We'll assume you're using Node 12 (but we've tested this back to Node 8 without issue). Please be sure you have the [Vue CLI tools](https://cli.vuejs.org/guide/installation.html) installed. If you don't just run this command from your terminal.

```
npm install -g @vue/cli
# OR
yarn global add @vue/cli
```

Now lets create our actual project. Vue CLI walks us through that process when we initialize a new project. Here are the configuration steps we've chosen:

```
vue create tozny-vue-auth-example
```

Selecting presets from the CLI

![](/files/-Ls3dd68Vo-AeYB50qZl)

We'll use Vuex, Vue Router, and Babel.

![](/files/-Ls3dsNeRhn5DZ91t6Zt)

The remaining configurations are left as the defaults, using history router and dedicated config files. Once that process has finished, we're ready to start coding. You can start your blank project by issuing the following commands:

```
cd tozny-vue-auth-example //or whatever you named the project
npm run serve
```

If successful you should get the standard Vue initialization app that looks like the image below.

![](/files/-Ls3eZrnYKg0e41pE7q0)

If you're seeing the webpage above when you navigate to the URL indicated in your terminal then we're in the right spot. Let's get our Tozny account configured and we'll be ready to code.

### Setting Up Tozny

Setting up your Tozny account is straight forward. We'll need to complete two steps, creating an account and creating a realm. Both are free - get started by heading over to the [Tozny Dashboard](https://dashboard.tozny.com) and either logging in or registering an account.

{% hint style="danger" %}
Be sure to use an email address you have access to. You need to verify your email before writes to the platform are enabled.
{% endhint %}

{% hint style="info" %}
A Realm defines where your users authenticate against. Once you create a realm you can then create your applications that users can authenticate against - in this tutorial we're using the Javascript SDK to authenticate against a realm. Realm names must be unique.
{% endhint %}

We need to complete a few things in our Tozny account:

* Create a realm in TozID
* Create an client application in the realm
* Set the application to allow \* for web origins

![Creating your TozID Realm](/files/-Lt_mPzZItqrhuSBYIF6)

{% hint style="info" %}
Click Manage Realm to access the below screens
{% endhint %}

![Creating a Client Application in your Realm](/files/-Ls43CL4Rk-lGvUL_ewu)

![Required Settings for You Application](/files/-Ls43GW-u7FP7w0vJDCr)

{% hint style="info" %}
Remember to set the redirect URI and web origins allowed and your redirect to localhost
{% endhint %}

### Authentication with TozID

Authentication in TozID happens a little differently than most authentication providers. We use cryptographic operations to derive keys from a username and password and issue signed requests to our Identity platform. If the request is successful we return encrypted data which contains your keys and your derived keys are then used to decrypt those encryption keys. We know, that sounds confusing, but it's all handled automatically by our SDK.

{% hint style="info" %}
Check out your network requests, your plain text passwords never leave your browser. We think that's pretty awesome. Tozny never stores them because we never see them.
{% endhint %}

Using our SDK you'll issue a standard looking login request and get back two important pieces of data. A tozStore credentials object and a standard JWT. You can use the JWT for authentication against any tranditional API backend - such as Laravel, Express, etc.

```javascript
import Tozny from 'tozny-browser-sodium-sdk'
const realmName = process.env.VUE_APP_REALM_NAME;
const appName = process.env.VUE_APP_APP_NAME;
const brokerUrl = process.env.VUE_APP_BROKER_URL;
const registrationToken = process.env.VUE_APP_REGISTRATION_TOKEN;

const realmConfig = {
    "realmName": realmName,
    "appName": appName,
    "brokerTargetUrl" : brokerUrl
}
const tozIDConfig = Tozny.Identity.Config.fromObject(realmConfig)
const tozId = new Tozny.Identity(tozIDConfig)
```

## Application Tutorial

### Application Scaffolding

Lets dive into the main coding exercise needed to make our application work. Since we used Vue CLI much of the boilerplate is already written and we can focus on the components we need to write. First off we'll need to install the JS Tozny SDK. Do that by going into your project directory and running the installation command.

```
npm install tozny-browser-sodium-sdk@2.0.0-alpha.1
```

We'll also create a few files to let users navigate our note taking app. The main files will be:\
\
1\. Login Page\
2\. Registration Page\
3\. Notes Dashboard (Authenticated)\
4\. Password Recovery Page\
5\. Router, store, and auth components as detailed below.

The end result of our project tree should resemble this:

![Ending project directory structure](/files/-LtVfAzY8U9nlI-a41g8)

### Environment Variables

Create a file named .env.local at your base directory which contains the following entries.

1. Registration Token
2. Realm Name
3. Client Application Name
4. Broker URL (where to be sent to complete a password recovery)

```
VUE_APP_REALM_NAME=
VUE_APP_APP_NAME=
VUE_APP_BROKER_URL=http://localhost:8080/reset
VUE_APP_REGISTRATION_TOKEN=
```

### Registration

{% tabs %}
{% tab title="Register.vue" %}

```javascript
<template>
  <div>
    <h2>Register</h2>
    <form @submit.prevent="submitRegister" autocomplete="off">
      <label>
        Email
      <input v-model="email">
      </label>
      <br>
      <label>
        Password
        <input v-model="pass" type="password">
      </label><br>
      <button type="submit">Register</button>
      <p v-if="error" class="error">Bad registration information or password.</p>
    </form>
  </div>
</template>

<script>
  import { mapActions, mapGetters } from "vuex";
  export default {
    data () {
      return {
        email: '',
        pass: '',
        error: false
      }
    },
    computed: {
      ...mapGetters([
        'loggedIn',
      ])
    },
    methods: {
      ...mapActions(['register']),
      async submitRegister () {
        this.error = false;
        if(!this.email || !this.pass){
          this.error = true;
          return;
        }
        try{
          await this.register({email: this.email, pass: this.pass})
          this.error = false;
          this.$router.replace(this.$route.query.redirect || '/dashboard')
        }catch(err){
          this.error = true;
        }

      }
    }
  }
</script>

<style>
  .error {
    color: red;
  }
</style>
```

{% endtab %}

{% tab title="vuex.js" %}

```javascript
// We've removed all of the unused methods from the registration
// flow here just to make it easier to follow.  The entire
// vuex store file is available in the Github repo that
// is linked below.

export default new Vuex.Store({
  state: {
    toznyClient: false,
    name: ''
  },
  mutations: {
    SET_TOZNY_CLIENT(state, payload){
      state.toznyClient = payload
    },
    SET_NAME(state, token) {
      const base64Url = token.split('.')[1]
      const base64 = base64Url.replace('-', '+').replace('_', '/')
      const claims = JSON.parse(window.atob(base64))
      state.name = claims['preferred_username'];
    },
  },
  actions: {
    async register({commit}, payload){
      try{
        const res = await tozId.register(payload.email, payload.pass, registrationToken, payload.email)
        localStorage.setItem('toznyClient',JSON.stringify(res.serialize()))
        commit('SET_TOZNY_CLIENT', res)
        const token = await res.token()
        commit('SET_NAME', token)

      }catch(err){
        return err;
      }
    },
  },
  getters: {
    loggedIn: state => !!state.toznyClient
  }
})
```

{% endtab %}
{% endtabs %}

### Login

{% tabs %}
{% tab title="Login.vue" %}

```javascript
<template>
  <div>
    <h2>Login</h2>
    <p v-if="$route.query.redirect">
      You need to login first.
    </p>
    <form @submit.prevent="submitLogin" autocomplete="off">
      <label>
        Email
        <input v-model="email" >
      </label>
      <br>
      <label>
        Password
        <input v-model="pass"  type="password">
      </label>
      <br>
      <button type="submit">login</button>
      <p v-if="error" class="error">Bad login information</p>
    </form>
    <button @click="resetPw">Forgot Password</button>
    <p>{{message}}</p>
  </div>
</template>

<script>
  import { mapActions, mapGetters } from "vuex";
  export default {
    data () {
      return {
        email: '',
        pass: '',
        error: false,
        message: ""
      }
    },
    computed: {
      ...mapGetters([
        'loggedIn',
      ])
    },
    methods: {
      ...mapActions(['login','requestReset']),
      async submitLogin () {
        try{
          await this.login({email: this.email, pass: this.pass})
          this.error = false;
          this.$router.replace(this.$route.query.redirect || '/dashboard')
        }catch(err){
          this.error = true;
        }
      },
      async resetPw(){
        this.message = "";
        try{
          await this.requestReset({email:this.email});
          this.message = "Please check your email";
        }catch(err){
          
        }
      }
    }
  }
</script>

<style>
  .error {
    color: red;
  }
</style>
```

{% endtab %}

{% tab title="vuex.js" %}

```javascript
// We've removed all of the unused methods from the registration
// flow here just to make it easier to follow.  The entire
// vuex store file is available in the Github repo that
// is linked below.

export default new Vuex.Store({
  state: {
    toznyClient: false,
    name: ''
  },
  mutations: {
    SET_TOZNY_CLIENT(state, payload){
      state.toznyClient = payload
    },
    SET_NAME(state, token) {
      const base64Url = token.split('.')[1]
      const base64 = base64Url.replace('-', '+').replace('_', '/')
      const claims = JSON.parse(window.atob(base64))
      state.name = claims['preferred_username'];
    },
  },
  actions: {
    async login({commit}, payload){
      try{
        const res = await tozId.login(payload.email, payload.pass)
        localStorage.setItem('toznyClient',JSON.stringify(res.serialize()))
        commit('SET_TOZNY_CLIENT', res)
        const token = await res.token()
        commit('SET_NAME', token)
      }catch(err){
        console.log("Bad password")
        return err;
      }
    },
  },
  getters: {
    loggedIn: state => !!state.toznyClient
  }
})
```

{% endtab %}
{% endtabs %}

### Forgot Password

Note that in order to use password recovery managed by Tozny you must grant us access to act as a broker and deliver the password reset email. If you'd like to manage this yourself just toggle the setting to off in the Dashboard. When you have this setting off Tozny is cryptographically isolated from your data and cannot recover or release your data.

{% tabs %}
{% tab title="request reset vuex.js" %}

```javascript
// We've removed all of the unused methods from the registration
// flow here just to make it easier to follow.  The entire
// vuex store file is available in the Github repo that
// is linked below.

export default new Vuex.Store({

  actions: {

    async requestReset({commit}, payload){
      try{

        // Requesting a reset from the TozID service and since
        // our realm is configured to let TozID broker the
        // reset our email will be delivered by Tozny 

        // (if you toggle OFF the setting in your realm settings then this will fail)

        const res = await tozId.initiateRecovery(payload.email)
      }catch(err){
        return err;
      }
    },

    
  },
  getters: {
    loggedIn: state => !!state.toznyClient
  }
})
```

{% endtab %}

{% tab title="ResetPassword.vue" %}

```
<template>
  <div>
    <h2>Reset Password</h2>
    <form @submit.prevent="submitReset" autocomplete="off" v-if="!error">
      <label>
        New Password
        <input v-model="pass"  type="password">
      </label>
      <br>
      <button type="submit">Reset Password</button>
    </form>
    <p v-if="error" class="error">Unable to verify the reset link.</p>
    
  </div>
</template>

<script>
  import { mapActions, mapGetters } from "vuex";
  export default {
    data () {
      return {
        email: '',
        pass: '',
        error: false,
        email_otp: '',
        note_id: ''
      }
    },
    computed: {
     
    },
    mounted(){
        this.error = false;
        if(this.$route.query.email_otp && this.$route.query.note_id){
            this.email_otp = this.$route.query.email_otp;
            this.note_id = this.$route.query.note_id;
        }else{
            this.error = true;
        }
    },
    methods: {
      ...mapActions(['completeRecovery']),
      async submitReset () {
        try{
          await this.completeRecovery({otp: this.email_otp, noteId: this.note_id, pass: this.pass})
          this.error = false;
          this.$router.replace('/login')
        }catch(err){
          this.error = true;
        }
      }
    }
  }
</script>

<style>
  .error {
    color: red;
  }
</style>
```

{% endtab %}

{% tab title="complete reset vuex.js" %}

```javascript
// We've removed all of the unused methods from the registration
// flow here just to make it easier to follow.  The entire
// vuex store file is available in the Github repo that
// is linked below.

export default new Vuex.Store({
  
  actions: {
    
    async completeRecovery({commit}, payload){
      try{
        // First we verify the query parameters from the recovery link
        // and pass them to the complete recovery method and then
        // the next function performs the password change
        const res = await tozId.completeRecovery(payload.otp, payload.noteId)
        await res.changePassword(payload.pass)
        return;
      }catch(err){
        return err;
      }
    },
  },
  getters: {
    loggedIn: state => !!state.toznyClient
  }
})
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="App.vue" %}

```javascript
<template>
  <div id="app">
    <h1>Auth Flow</h1>
    <ul>
      <li>
        <router-link v-if="loggedIn" to="/logout">Log out</router-link>
        <router-link v-if="!loggedIn" to="/login">Log in</router-link>
      </li>
      <li v-if="!loggedIn">
        <router-link v-if="!loggedIn" to="/register">Register</router-link>
      </li>
      <li>
        <router-link to="/dashboard">Dashboard</router-link>
        (authenticated)
      </li>
    </ul>
    <template v-if="$route.matched.length">
      <router-view></router-view>
    </template>
    <template v-else>
      <p>You are logged {{ loggedIn ? 'in' : 'out' }}</p>
    </template>
  </div>
</template>

<script>
  import { mapState, mapGetters } from "vuex";
  export default {
    data () {
      return {
       
      }
    },
    computed: {
      ...mapGetters([
        'loggedIn',
      ])
    },
  }
</script>
<style>
  html, body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    color: #2c3e50;
  }

  #app {
    padding: 0 20px;
  }

  ul {
    line-height: 1.5em;
    padding-left: 1.5em;
  }

  a {
    color: #7f8c8d;
    text-decoration: none;
  }

  a:hover {
    color: #4fc08d;
  }
</style>
```

{% endtab %}
{% endtabs %}

#### Dashboard.vue

Here is where we're actually reading and writing encrypted data from Tozny. One of the key benefits of Tozny's platform is that Tozny never has access to key material so there is no ability to leak decrypted data - all of the encryption and decryption operations happen client side (in your browser in this case).

{% tabs %}
{% tab title="Dashboard.vue" %}

```javascript
<template>
  <div>
    <h2>Dashboard</h2>
    <p>You're logged in {{name}}!</p>

    <h3 v-if="notes.length > 0">Your Notes</h3>
    <ul>
    <li v-for="item in notes" :key="item.meta.recordId">
      {{item.data.note}}
    </li>
    </ul>
    <h3>Write New Secret Note</h3>
    <div class="note-area">
      <textarea v-model="note" />
      <button @click="writeNote">Write Note</button>
    </div>
    <div>
      <button @click="showToken">Show JWT</button>
      <div>{{token}}</div>
    </div>
  </div>
</template>
<script>
  import auth from '../auth'
  import { mapState } from "vuex";
  export default {
    data () {
      return {
        notes: [],
        loading: false,
        token: "",
        note: ""
      }
    },
    computed: {
        ...mapState(["toznyClient", "name"])
    },
    mounted(){
      
      this.getNotes();
      
    },
    methods: {
      async getNotes(){
         let records = await this.toznyClient.storageClient.query(true, null, null, 'note').next();
         this.notes = records;
      },
      async writeNote(){
        await this.toznyClient.storageClient.write('note', {'note': this.note});
        this.getNotes();
      },
      async showToken(){
        const token = await auth.getToken();
        this.token = token;
      }
    }
  }
</script>
<style scoped>
  .note-area{
    width: 400px;
    display: flex;
    flex-direction: column;
  }

</style>
```

{% endtab %}
{% endtabs %}

####

#### Vuex Store

{% tabs %}
{% tab title="store/index.js" %}

```javascript
import Vue from 'vue'
import Vuex from 'vuex'
import Tozny from 'tozny-browser-sodium-sdk'
const realmName = process.env.VUE_APP_REALM_NAME;
const appName = process.env.VUE_APP_APP_NAME;
const brokerUrl = process.env.VUE_APP_BROKER_URL;
const registrationToken = process.env.VUE_APP_REGISTRATION_TOKEN;

const realmConfig = {
    "realmName": realmName,
    "appName": appName,
    "brokerTargetUrl" : brokerUrl
}
const tozIDConfig = Tozny.Identity.Config.fromObject(realmConfig)
const tozId = new Tozny.Identity(tozIDConfig)

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    toznyClient: false,
    name: ''

  },
  mutations: {
    SET_TOZNY_CLIENT(state, payload){
      state.toznyClient = payload
    },
    SET_NAME(state, token) {
      const base64Url = token.split('.')[1]
      const base64 = base64Url.replace('-', '+').replace('_', '/')
      const claims = JSON.parse(window.atob(base64))
      state.name = claims['preferred_username'];
    },
    LOGOUT(state){
      delete localStorage.clear();
    }
    
  },
  actions: {
    async setToznyClient({commit}, payload){
      commit('SET_TOZNY_CLIENT', payload)
      
    },
    logout({commit}){
      commit('LOGOUT')
    },
    async rehydrateTozny({commit}){

        const client = tozId.fromObject(localStorage.getItem('toznyClient'))
        commit('SET_TOZNY_CLIENT', client)
        const token = await client.token()
        commit('SET_NAME', token)
    },
    async login({commit}, payload){
      try{
        const res = await tozId.login(payload.email, payload.pass)
        localStorage.setItem('toznyClient',JSON.stringify(res.serialize()))
        commit('SET_TOZNY_CLIENT', res)
        const token = await res.token()
        commit('SET_NAME', token)
        

      }catch(err){
        console.log("Bad password")
        return err;
      }
    },
    async requestReset({commit}, payload){
      try{

        // Requesting a reset from the TozID service and since
        // our realm is configured to let TozID broker the
        // reset our email will be delivered by Tozny 

        // (if you toggle OFF the setting in your realm settings then this will fail)

        const res = await tozId.initiateRecovery(payload.email)
      }catch(err){
        return err;
      }
    },
    async completeRecovery({commit}, payload){
      try{
        // First we verify the query parameters from the recovery link
        // and pass them to the complete recovery method and then
        // the next function performs the password change
        const res = await tozId.completeRecovery(payload.otp, payload.noteId)
        await res.changePassword(payload.pass)
        return;
      }catch(err){
        return err;
      }
    },
    async register({commit}, payload){
      try{
        const res = await tozId.register(payload.email, payload.pass, registrationToken, payload.email)
        localStorage.setItem('toznyClient',JSON.stringify(res.serialize()))
        commit('SET_TOZNY_CLIENT', res)
        const token = await res.token()
        commit('SET_NAME', token)

      }catch(err){
        return err;
      }
    },
    
  },
  getters: {
    loggedIn: state => !!state.toznyClient
  }
})

```

{% endtab %}
{% endtabs %}

#### Vue Router

{% tabs %}
{% tab title="router/index.js" %}

```javascript
import Vue from 'vue'
import Router from 'vue-router'
import Dashboard from '@/components/Dashboard.vue'
import Login from '@/components/Login.vue'
import ResetPassword from '@/components/ResetPassword.vue'
import Register from '@/components/Register.vue'
import store from '../store'
import auth from '../auth'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: __dirname,
  routes: [
    { path: '/dashboard', component: Dashboard, beforeEnter: requireAuth },
    { path: '/login', component: Login, beforeEnter: authRedirect },
    { path: '/reset', component: ResetPassword },
    { path: '/register', component: Register, beforeEnter: authRedirect },
    { path: '/logout',
      beforeEnter (to, from, next) {
        store.dispatch("logout").then(
          location.reload()
        )
        
      }
    }
  ]
})

// If a user attempts to access login or register let's check if they are
// already authenticated and properly route them back to the dashboard

async function authRedirect (to, from, next) {
  if(!store.state.toznyClient && localStorage.getItem('toznyClient')){
    await store.dispatch('rehydrateTozny')
  }
 
  if (!store.state.toznyClient) {
    next()
  } else {
    next({
      path: '/dashboard'
    })
  }
}

// Before we allow access to protected routes the application should
// validate that the user is properly authenticated use our vuex 
// getter that is defined in the store

async function requireAuth (to, from, next) {
  if(!store.state.toznyClient && localStorage.getItem('toznyClient')){
    await store.dispatch('rehydrateTozny')
  }
 
  if (!store.state.toznyClient) {
    next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  } else {
    next()
  }
}
```

{% endtab %}
{% endtabs %}

#### TozID Auth

{% tabs %}
{% tab title="auth.js" %}

```javascript
// This auth file is intentionally kept simple and designed to only
// return a standard JWT on demand.  The hydration from from
// local storage is done in our vuex store as an action

import store from './store'

export default {

  async getToken () {
    // Call this to get a token to set as a global bearer token when calling your own API
    // Tozny will handle automatically refreshing this token for you if needed

    try{
      const token = await store.state.toznyClient.token()
      return token;
    }catch(err){
      console.log("Unable to get token")
      return false;
    }
  },
}
```

{% endtab %}
{% endtabs %}

### Wrapping Up

Putting all of this together should result in you being able to login, register, and read and write notes that only your user can decrypt! If you run into any questions just shoot us an email at <support@tozny.com> and we'll be happy to help.

Grab the full source code for this project on our github - <https://github.com/tozny/tozny-vue-auth-example>


# Quickstart

Securely store your sensitive information with our end to end encryption

## Overview

With TozStore securing your data is easy, as our platform and SDKs do all of the cryptography for you. Integrating TozStore is a simple process:

1. Create an account at the [Tozny Dashboard](https://dashboard.tozny.com/login) and create your registration token [here](https://dashboard.tozny.com/clients/client-reg-tokens). This registration token is what lets you create your clients.
2. Using the SDK of your choice, create a client with your new registration token and begin writing [encrypted data](/toz-store/core-concepts#how-is-your-data-secured) to TozStore.

### 1. Install SDK

We provide a number of SDK's in different languages, feel free to choose the one that best suits your needs.

|                                                      |                                                    |
| ---------------------------------------------------- | -------------------------------------------------- |
| [Python](https://github.com/tozny/e3db-python)       | [Javascript](https://github.com/tozny/js-sdk)      |
| [Ruby](https://github.com/tozny/e3db-ruby)           | [Go](https://github.com/tozny/e3db-go)             |
| [PHP](https://github.com/tozny/e3db-php)             | [CLI](https://github.com/tozny/e3db)               |
| [Java (Android)](https://github.com/tozny/e3db-java) | [iOS (Swift)](https://github.com/tozny/e3db-swift) |

### 2. Create a Client

Creating a client is a quick process, but remember that these credentials are private and should be handled with care. If these credentials are lost there is no way to recover your data, as we do not store them by default.

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

```python
import e3db

token = 'YOUR_REGISTRATION_TOKEN_HERE'
client_name = 'example name'

public_key, private_key = e3db.Client.generate_keypair()

# Register your client
client_info = e3db.Client.register(token, client_name, public_key)

config = e3db.Config(
    client_info.client_id,
    client_info.api_key_id,
    client_info.api_secret,
    public_key,
    private_key
)

# To save this Configuration to disk, do the following:
config.write()

# Instantiate your client to communicate with TozStore
client = e3db.Client(config())
```

{% endtab %}
{% endtabs %}

### 3. Encrypt Your Data

Tozny's SDKs handle the encryption for you, all you need to provide is the data. See[ Record Structure](/toz-store/core-concepts#data-record-structure) for details on how you can best structure your data.

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

```python
import e3db

client = e3db.Client(
  # config
)

record_type = 'contact'
data = {
    'first_name': 'Jon',
    'last_name': 'Snow',
    'phone': '555-555-1212'
}

metadata = {
  'house' : 'Stark'
}

record = client.write(record_type, data, metadata)
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const e3db = require('e3db')

let client = new e3db.Client(/* config */)

async function main() {
  let data = {
    'first_name': 'Jon',
    'last_name': 'Snow',
    'phone': '555-555-1212',
  }
  let metadata = {
    'house' : 'Stark'
  }
  let record = await client.write('contact', data, metadata)

  console.log('Wrote record ' + record.meta.recordId)
}
main()
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
$data = [
    'name' => 'Jon Snow',
    'what_he_knows' => 'Nothing',
];
$metadata = [
    'house' => 'Stark'
];

// 'test-contact' represents our data type
$record = $client->write('test-contact', $data, $metadata);

//record contains the newly created value
$record_id = $record->meta->record_id;
?>
```

{% endtab %}

{% tab title="Go" %}

```go
// Create data for a record
var recordData map[string]string
recordType := "contact"
recordData["first_name"] = "Jon"
recordData["last_name"]  = "Snow"
recordData["phone"]      = "555-555-1212"

// Create optional metadata for the record
//(metadata can be used for searching)
var metadata map[string]string
matadata["realm"] = "The North"
metadata["pet"]   = "Ghost"

// Encrypt and save the record
recordID, err := client.Write(
  context.Background(), 
  recordType, 
  recordData, 
  metadata
  )
if err != nil {
    //Error handling omitted
}
fmt.Println("Wrote record: " + recordID)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
record = client.write('contact', {
    :first_name => 'Jon',
    :last_name => 'Snow',
    :phone => '555-555-1212'
  })
printf("Wrote record %s\n", record.meta.record_id)
```

{% endtab %}

{% tab title="Java" %}

```java
  Client client = ...; // Get a client instance

  Map<String, String> lyric = new HashMap<>();
  lyric.put("line", "Say I'm the only bee in your bonnet");
  lyric.put("song", "Birdhouse in Your Soul");
  lyric.put("artist", "They Might Be Giants");

  String recordType = "lyric";

  client.write(recordType, new RecordData(lyric), null, new ResultHandler<Record>() {
      @Override
      public void handle(Result<Record> r) {
        if(! r.isError()) {
          // record written successfully
          Record record = r.asValue();
          // Log or print record ID, e.g.:
          System.out.println("Record ID: " + record.meta().recordId());
        }
        else {
          // an error occurred
          throw new RuntimeException(r.asError().other());
        }
      }
    }
  );
```

{% endtab %}

{% tab title="Swift" %}

```swift
// Wrap message in RecordData type to designate
// it as sensitive information for encryption
let recordData = RecordData(cleartext: ["SSN": "123-45-6789"])

// Can optionally include arbitrary metadata as `plain`
// where neither keys nor values are encrypted
e3db.write(type: "UserInfo", data: recordData, plain: ["Sent from": "my iPhone"]) { result in
    switch result {

        // The operation was successful, here's the record
        case .success(let record):

            // `record.meta` holds metadata associated
            // with the record, such as type.
            print("Wrote record! \(record.meta.recordId)")

        case .failure(let error):
            print("An error occurred attempting to write the data: \(error)")
        }
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Have questions? Contact us at <help@tozny.com>
{% endhint %}


# Core Concepts

## Application Level Encryption

TozStore provides application-level encryption, which secures your data for its entire life-cycle. Data gets encrypted where it is generated (written) and decrypted where it is consumed (read), providing end-to-end encryption. Data records are encrypted individually, providing powerful, fine-grained access control for sharing and revoking access to data. As a result, the data carries its own security no matter what infrastructure it crosses. Even if data were to leak outside of network infrastructure, gets backed up to an insecure location, or is hacked by an online adversary, the encrypted data remains secure.

Systems that take advantage of encryption to strengthen security typically use infrastructure-level encryption, but not application-level encryption. With infrastructure-level encryption networking or database infrastructure is encrypted, and so data is protected within the infrastructure; however, when the data leaves this infrastructure, or the infrastructure is compromised, security is lost. Infrastructure-level encryption approaches, like Virtual Private Networks (VPNs), protect data in transit and can control access to a network. Anyone with access to the network, has access to the services and all data within those services. Data will no longer be secure if data leaks outside of the network infrastructure or an attacker bypasses standard access control mechanisms.

Application-level encryption provides greater security than infrastructure-level encryption, because the data itself is protected through encryption.

TozStore makes end to end encryption easy with our SDK's and backend platform. The SDK's handle all of the hard parts of application-level encryption for you, so you build your application knowing its data will be secure. Tozny does not have access to your encryption keys and cannot read, recover, or decrypt your data. The real time encryption services provided by Tozny allow you protect plain text, json objects, or large files with minimal overhead. Use TozStore as a second database in your applications for all of your sensitive information.

{% hint style="info" %}
TozStore can be used as a real time key value store for your sensitive information. Simply store the returned record ID and use our SDK's to compute on the data at run time.
{% endhint %}

### How is your data secured?

We've gone over how data in TozStore is structured, but glossed over the internals of how this data is secured. Three main keys are used to encrypt and protect your data; they are your client key, the access key, and the data key. Starting from the lowest level your data comes in as a plain-text string map.

```python
my_data = { 'key_1':'value_1' , 'key_2':'value_2', 'key_3':'value_3', ... }
```

From here a symmetric data key is generated for each of the fields in your data object, and it is used to encrypt the incoming plaintext value.

```python
encrypted_value_1 = encrypt(datakey_1, value_1)
encrypted_value_2 = encrypt(datakey_2, value_2)
encrypted_value_3 = encrypt(datakey_3, value_3)
...
```

Each data key is then encrypted with the record-type level access key, and stored along with the data.

Finally, the client key is used to encrypt the access key. This encrypted access key is stored in TozStore and associated with a specific record type. The access key can be pulled down later and be used to encrypt future records that share the same record type. The Client private key is maintained and kept a secret by you, the user of the SDK. This ensures that you are the sole owner of the data written to TozStore. No one else is able to decrypt and see the data within TozStore, but you can give access to other users through sharing.

### Data Ownership

You are the sole owner of any data that you write to TozStore. More specifically the client that writes data is the only client who can decrypt that data. This is important to remember when creating applications; for example, each device using a mobile application that leverages TozStore will be the only device that can decrypt that data. If another service, your backend, needs to access that data, then access will have to be shared from the device client to your backend client.

{% hint style="info" %}
To read data between clients, the writer of the data must share records with the reader. All TozStore SDK's provide services to share (and revoke) records between clients.
{% endhint %}

### Sharing

Our platform allows you to share your encrypted data without needing to send the encrypted data, or worse un-encrypted data, directly to a third party. Instead you can both leverage TozStore to read encrypted data directly from our database. The platform shares records linked by their record type with another client in TozStore.\
\
When you share with other users, behind the scenes you're pulling down the encrypted access key from TozStore, decrypting it, and re-encrypting it with the public key of the client you want to share the records with. This new encrypted key, along with an access control policy, is placed into TozStore allowing the third party client to download and decrypt your records. This way you have full control over your data, and it remains encrypted until you or an authorized party decrypts it locally with your respective private keys. See it in action [here](/toz-store/core-concepts/using-tozstore#sharing).


# Using TOZ Store

### Data Structure

Next, you need to determine what structure would be best for your data records. Data records within TozStore are composed of three main fields: the **record type**, the **un-encrypted metadata**, and the **encrypted data object**. These three fields are what you provide when writing records, with unencrypted meta being optional.

The record type is used to group records together for the purpose of sharing. TozStore's [sharing process](/toz-store/core-concepts#sharing) allows you to share record types between clients. Access control to specific records is all or nothing based off of record types, so be sure to keep that in mind when structuring your data.

The un-encrypted metadata is an optional field that can be used to search for your records. Some intrinsic meta is generated when you create your record such as the record id (UUID), the time it was created, the last time it was modified, etc. You may want more friendly ways to retrieve your data in the future, and this is where metadata comes in (remember the data is encrypted and only you can decrypt it). The metadata is stored in plain-text giving you the ability to [search](/toz-store/core-concepts#searching-beta) upon them with the TozStore SDK's. Keep in mind these are plain-text and should not be used to store sensitive data.

Finally, the encrypted data object is where your sensitive data lives. The structure of this object is a string to string key-value store, where the value is encrypted and the key is un-encrypted. Here is a more general overview of how [TozStore works](/toz-store/core-concepts#how-do-we-encrypt-data).

```python
my_data = { 'some_plain_key':'encrypted_sensitive_value', ... }
```

Below is a simple example showing you how to write a record in TozStore.

```javascript
  //data will be encrypted as the write operation moves through the SDK
  let data = {
    'first_name': 'Jon',
    'last_name': 'Snow',
    'phone': '555-555-1212',
  }
  
  //metadata is left in plain text to enable queries on your data
  let metadata = {
    'house' : 'Stark'
  }
  
  //record types help to group your data together
  let record_type = 'contact'
  let record = await client.write(record_type, data, metadata)
```

{% hint style="info" %}
Note that your data and metadata objects should be flat. Treat TozStore as a string to string key value store.
{% endhint %}

### Sharing

Sharing in TozStore is how you grant access to your data to other clients. These can be clients within your account or cross account. Sharing is great since it retains control of the data within your account. You can revoke access at any time and this does not duplicate the data itself. All access to records is handled through cryptographic controls. Here's an example of how sharing data works with TozStore.

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

```python
import e3db
from e3db.types import Search

# Instantiate your client
client = e3db.Client(config())

# For this example, instantiate a third party client
third_party = e3db.Client(third_party_config())

record_type = 'share_me'
client.share(record_type, third_party.client_id)
client.write(record_type, {'test':'data'})

# Obtain records written by client from the third_party client
results = third_party.search(Search(include_all_writers=True) \
                                .match(record_types=[record_type]))

for r in results:
   print(r.to_json())
```

{% endtab %}
{% endtabs %}

### Searching (Beta)

Within TozStore your data is encrypted and can't be searched by us, but the meta you provide is searchable. We support a number of search options on this meta that allow you to parse through your data without exposing the secure information.\
\
To recap record creation, when you write a record you have the option to provide un-encrypted meta that is stored along with your data. This meta is accepted in format of a string to string map, like the format of encrypted data. This plain meta map can be used for searching, but the key and values of the mapping are also expanded into additional searchable fields.

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

```python
import e3db
from e3db.types import Search

# Instantiate your client
client = e3db.Client(config())

apricot_data = {"recipe": "one ripe apricot"}
apricot_plain = {"flavor":"apricot"}
client.write("jam", apricot_data, apricot_plain)

strawberry_data = {"recipe": "many strawberries"}
strawberry_plain = {"flavor":"strawberry"}
client.write("jam", strawberry_data, strawberry_plain )

# Get our strawberry record
strawberry_results = client.search(Search().match(plain=strawberry_plain))
for jam in strawberry_results:
   print(jam.to_json())
   
# match records where record_types == "jam" AND values == "apricot"
apricot_query = Search().match(condition="AND", 
                              record_types=["jam"], 
                              values=["apricot"])
apricot_results = client.search(apricot_query)
for jam in apricot_results:
   print(jam.to_json())
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The examples above highlights some simple searches on TozStore. Currently, Search is only supported in the [Python SDK](https://github.com/tozny/e3db-python#searching-records) and you can find more complex examples that include time filters, fuzzy, regex, and other meta fields on the Github page.
{% endhint %}


# Data Structure

### Basic Overview

Data records are the basis of what makes TozStore. You can store any data you'd like as part of these record structures and work much like a NoSQL store. However, there are some key differences you should consider when developing your application. Records are stored with a **record type** which is a string value provided at write time which helps you group your data. Record types are essentially a way to represent a collection of certain kinds of records.

### Data

It's important to know what pieces of your data are encrypted when using TozStore. Let's take a look at an example using Social Security Numbers. In the code snippet below we've got an object that holds sensitive information that needs to be encrypted and stored.

```javascript
{ "person" : "Jon Snow", "ssn" : "555-33-2222" }
```

When writing this to TozStore you may call our write function like so:

```javascript
client.write("person", {"name":"Jon Snow","ssn" : "555-33-2222"})
```

In the code example above we've said that the **record type** is "person" and the data is a key value set that includes "name" and "ssn". The field names "name" and "ssn" are not encrypted while the person's name and actual SSN are encrypted.

### Metadata

TozStore also allows you to pass in a third argument we call metadata. This data is also stored unecrypted which allows you to query against it. This makes it easy to find data based on information about the record without needing to expose the sensitive information directly. Let's expand our example.

```javascript
client.write("person", {"name":"Jon Snow","ssn" : "555-33-2222"},{ "house" : "stark"})
```

Now that we've added a key value set of data as metadata we can query for all of our records that are of "house" key equal to "stark". You can include any number of key:value pairs when writing records.


# Account Details

### Generating Client Credentials

Regardless of how you choose to generate client credentials and register clients, you will need to use the Tozny Dashboard, a collection of Tozny tools. Create a free account with [Tozny](https://dashboard.tozny.com/). Save this link for easy, future use.

The first way to generate client credentials is go to the Dashboard then Clients tab and click the action button to create a new client, then gather the client's credentials presented as a JSON. In this one action, the Dashboard will generate the needed keys, register the client with TozStore and receive the resulting TozStore client ID and credentials needed to authenticate with the Tozny API. Additionally an encrypted back-up of the client's credentials in TozStore. To avoid having a backup created read on for how to create clients programatically below.

This same workflow can be implemented using a TozStore SDK to dynamically generate client credentials, register, and back-up clients. However, you may be less concerned with being able to retrieve lost private keys and more concerned with stronger security. In this case, you may want a client's private key to only ever be available locally, so you will not want to back-up client credentials in TozStore. In this case, you can dynamically generate client credentials and register clients without backing up client credentials in TozStore.

Dynamically generating client credentials using a TozStore SDK requires first generating a client registration token using the Dashboard. When you generate client credentials and register clients with the Dashboard, your Tozny account username and password enable access to the Tozny API. A client registration token stands in for this layer of authentication.

Tozny provides SDK in various languages. All of our SDK's are open source and available on GitHub. Below are some quick links to each of the languages we support.

### Client Credentials & Key Management

Key management is a foundational security concern while using TozStore. Most significantly, client credentials include a private key that is critical for security. Making a private key public compromises the security provided by TozStore the same way leaving a key in a lock would undermine the security provided by the lock. Losing access to keys also poses the risk of losing access to data, as data encrypted with a client's credentials cannot be decrypted without the relevant client credentials.

The security of data stored using TozStore depends upon the key management practices used surrounding TozStore tools. The section on Key Management in this guide offers advice on making a key management plan. In this section, the team at Tozny who created the TozStore system will share some of our concerns, best practices, and decisions regarding key management. Hopefully, this will help you confidently and quickly decided on the key management plan that is right for your system.

Once you have decided on a way to manage your client credentials, TozStore provides a few ways to generate client credentials. Clients have the option of whether to store an encrypted back-up of their credentials on the server. In choosing a workflow for registering clients, consider the balance between concerns over the security of private keys and the ability to recover lost private keys.


