The Portis platform provides convenient access to the Ethereum network from any web application.
Your dApp (decentralized application) communicates with the Portis SDK using standard web3.js API calls, meaning it will work automatically with your existing web application.
Users don’t have to install anything in advance to use your dApp. With Portis, your dApp already comes bundled with a solution by offering them a simple in-browser email/password login method which feels familiar.
Once a user creates a wallet, it is immediately encrypted using AES-GCM. The Portis server only stores encrypted wallets, so we can enable users to easily use the same account across different devices, all without compromising security. Every transaction is signed client-side by the user, meaning the Portis server only relays signed transactions (i.e it can't modify them).
Our code underwent rigorous third party security audits. The SDK is published open source because we believe that is the best way to reach a truly secure codebase. In addition, we want to involve developers as much as possible and welcome any and all comments / pull requests.
For security reasons, dApps using Portis must run over HTTPS.
To begin using Portis in your dApp, the Portis SDK JavaScript code should be loaded into your dApp's code. There are several ways to carry this out:
The recommended method of loading Portis is by installing the portis
npm package:
$ npm install portis
You can also include the bundled portis.js file hosted on jsdelivr's CDN:
<script src="https://cdn.jsdelivr.net/npm/portis/dist/bundle.min.js"></script>
We also provide a way to deploy Portis via bower. Useful if you want serve your own scripts (instead of depending on our CDN) and maintain a bower.json
with a list of dependencies and versions (adding the --save
flag would automatically add it to bower.json
).
$ bower install portis --save
<script src="/bower_components/portis/dist/bundle.min.js"></script>
Portis should be imported into the same part of the code where you initialize web3
To use Portis with CommonJS imports:
var PortisProvider = require('portis').PortisProvider;
To use Portis with Typescript / ES2015 imports:
import { PortisProvider } from 'portis';
To use Portis from CDN:
var PortisProvider = window.Portis.PortisProvider;
Register your dApp on the Portis platform - https://app.portis.io/dashboard.
In this page, you will be able to manage all of your dApps which are powered by Portis.
Inside your dApp's info page you will see your API Key. You will need to provide that key when initializing Portis as your Web Provider
.
The API Key is not secret (as it is being sent from the client), its goal is to verify that the dApp using Portis has been registered and is approved.
Once Portis has been imported, you should set it up as your fallback Web3 Provider
:
// Check if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
web3js = new Web3(web3.currentProvider);
} else {
// Fallback - use Portis
web3js = new Web3(new PortisProvider({
apiKey: 'YOUR_DAPP_API_KEY'
}));
}
// Now you can start your app & access web3 freely:
startApp();
This will set Portis as the fallback for when Mist/MetaMask or any other pre-installed web3 providers are not available.
If the Portis provider was injected properly, then isPortis
will return true
web3.currentProvider.isPortis
Here is an example. (Hit "Run" if you don't see anything, and make sure you either disable MetaMask or use private mode on your browser)
If you need the user's address, perhaps to authenticate them into your website, you would use the regular web3.eth.getAccounts
method. Nothing special here:
// ES7+ async/await
const accounts = await web3.eth.getAccounts()
const [address] = accounts
// ES6 Promise
web3.eth.getAccounts().then(accounts => {
const address = accounts[0]
})
Note that unlike MetaMask, Portis only supports a single wallet per account.
More info on personal_sign
here: https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
Again, nothing special here! Use the regular web3.currentProvider.sendAsync
method:
web3.currentProvider.sendAsync(
{
id: 1,
method: 'personal_sign',
from: address,
params: [data, address, password],
},
(err, result) => {
if (err) {
throw new Error(err)
}
authenticateUser(result.result)
},
)
A configuration options object should be passed along when initializing the Portis provider:
web3js = new Web3(new Portis.PortisProvider({
apiKey: 'YOUR_DAPP_API_KEY',
network: 'ropsten'
}));
Type: String
Default Value: null
Required: true
The API Key of your dApp, provided in the Portis dashboard after registering your dApp.
When running your dApp on localhost, Portis does not require the API Key.
Type: String
Default Value: mainnet
Required: false
Determines which Ethereum network all web3 methods will communicate with. You can set Portis to work with any one of the following networks:
- mainnet
- ropsten
- kovan
- rinkeby
- sokol (POA Network)
- core (POA Network)
Type: String
Default Value: null
Required: false
The API Key of your Infura account. If provided, Infura will serve as the provider node for all outgoing communication with the Ethereum network.
Type: String
Default Value: null
Required: false
The URL of a custom provider node. If provided, that endpoint will serve as the provider node for all outgoing communication with the Ethereum network.
The valid types are HttpProvider
, WebsocketProvider
and IpcProvider
, as defined in the web3js documentation.
Example:
HttpProvider
:
providerNodeUrl: 'http://localhost:8545'
Type: String[]
Default Value: null
Required: false
When a person logs into your DApp via Portis you can request to access a subset of that person's data stored on Portis using the scope
parameter. Its value is an array of strings of the requested permissions. As of now, the only supported permissions string is email
. The user can either approve or decline the permissions request. If they approve, their email will be returned in the login
event.
Example:
web3js = new Web3(new Portis.PortisProvider({
apiKey: 'YOUR_DAPP_API_KEY',
network: 'ropsten',
scope: ['email']
}));
If you already know the user's email address, you can use this method to pre-populate the email field in the login and register pages.
When editable
is false, all email inputs will be disabled. The default value of editable
is true
.
Example:
web3.currentProvider.setDefaultEmail('[email protected]');
You may want to show a user their Portis account without necessarily having them carry out an action (e.g. signTransaction). Calling this method will open the Portis window. The provided callback function will be called once the window has been closed explicitly by the user.
Example:
web3.currentProvider.showPortis(() => {
console.log('Portis window was closed by the user');
});
The Portis provider emits events using the .on('eventName', callback) scheme.
Example:
web3.currentProvider.on('event-type', result => {
console.log('event-type was thrown');
});
When a DApp calls any web3 method which requires the user to login (for instance getAccounts), there is no way for the DApp to know if the callback was successful since the user just logged in to Portis successfully, or if they were already logged in, and it was invoked successfully without having to show the login window to the user.
The login
event allow DApps to detect when a user explicitly logged in successfully to their Portis account. The callback method will return an object containing:
provider
: will always have the valueportis
address
: the wallet address of the logged in useremail
: if theemail
permission was requested in the scope, and the user approved sharing it, this value will contain the user's email address
When a user initiates an ETH purchase through our third-party provider, the purchase-initiated
event is thrown.
The callback method will return an object containing two values:
provider
: will always have the valueportis
purchaseId
: a unique indentifier which can be used to poll the purchase status, as documented in the dashboard.
Each new account is automatically loaded with $1 worth of Ether, free of charge. Our goal is to provide the best user experience to your users, so we want to make sure that the first time they sign a transaction goes as smooth as possible.
To prevent people from abusing this mechanism, we require a phone number when creating an account (a PIN is sent via SMS to that number to complete registration).
We realize that some users might feel uncomfortable about providing their phone number. Also, this requirement poses an issue when testing, where you may want to easily generate a lot of different accounts.
Therefore, it is not mandatory to provide a phone number at the final step of registration. The new account simply won't be funded with the $1 worth of Ether.
For security reasons, Portis supports "evergreen" browsers - the last versions of browsers that automatically update themselves.
Edge |
Firefox |
Chrome |
Safari |
iOS Safari |
Opera |
---|---|---|---|---|---|
last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions | last 2 versions |