StellarExpertID provides a safe and reliable way to use your Stellar accounts without trusting anyone with your secret key. All sensitive data is encrypted with your password and securely stored in the browser.

Key features

  • Secure key management – your secret key is never exposed to third-party services.
  • Secure transaction signing – transactions are signed without exposing a secret key.
  • SEP-0007 compatible – can be used to handle "web+stellar" links.
  • Web apps Single Sign-On – login to third-party websites, just like with Google or Facebook OAuth.
  • Two-factor authorization support – provides another level of protection for your accounts.
  • Digital identity – associate a nickname, email, or avatar with your account address (or leave it blank if you prefer to stay incognito).
  • Multi-account support – use multiple accounts and switch them when you need it.
  • Message signing tools – sign and verify arbitrary data with your private keys.
  • Inflation voting – vote for inflation pools with a single button click without worries for your funds' safety.
  • Federation support – make use of a human-friendly address for your account.
  • Works everywhere – the same account operates seamlessly via desktops, smartphones, and tablets.

Intents

There are 4 main groups of intents:

  1. Request transaction signing. The signer app prepares and signs a transaction which then can be returned to the initiator website or submitted directly to the network.
  2. Request specific action. Either "transfer funds", "vote for inflation pool", or "establish a trustline". Each action is effectively a simplified wrapper for the transaction signing request. No custom logic or even JS SDK is required on the initiator side.
  3. Request information. The website may request a user's personal info (email, avatar) or Stellar account public key.
  4. Request cryptographic signature of the arbitrary data. The website may request a crypto signature to verify a keypair ownership (authentication, secure messages exchange etc).

Authorization flows

The signer supports two authorizaton flows: an implicit flow and callback flow.

Implicit flow

A popup window with request details is shown each time an initiator website requests the action.

  1. A user invokes some action on the third-party website (a wallet, DEX interface, inflation pool etc). Let's say, he wants to create an offer.
  2. The website prepares the requested transaction and it's XDR representation in base64 format.
  3. The website initiates the intent (see intent list in the project description) using js module that provides an interface for all supported intents.
  4. The interface module opens a new pop-up window pointing to id.stellar.expert. All intent parameters are serialized and transmitted in a form of GET parameters. So the full URL will look like https://id.stellar.expert/confirm?intent=tx&network=testnet&xdr=AAAAALPZeTF82....
  5. Signer application reads parameters from the URL and asks the user for a confirmation.
  6. The user chooses a keypair from the list of stored accounts (or adds a new one) and confirms the action.
  7. The signer app signs the transaction the same way any other wallet do it.
  8. The signed transaction is serialized into XDR as TransactionEnvelope and transmitted back to the opener site in base64 encoding via the built-in browser postMessage mechanism.
  9. The third-party website receives a signed transaction envelope and may choose either to submit it to the network or store somewhere in case if the tx needs more signatures or if it has time bounds set.

Intent confirmation dialog always contains extended request information, including intent description (like "Sign transaction"), initiator website ("origin: example.com"), risk level ("high", "medium", or "low"), information about personal data disclosure (only for personal_info intent), and safety status ("safe" or "potentially unsafe"). Intent-specific details allow a user to review the request before confirmation. For instance, a dialog with sing_tx intent displays full transaction information including all meaningful properties and the list of operations in a human-friendly format adapted for the ordinary users.

Callback flow

The callback flow supports Stellar SEP-0007 link format.
Instead of showing a popup authorization dialog, it redirects the browser to the signer page.
A signed transaction can be either submitted to the network or returned to the specified callback URL via POST request.

Technical details

The project consists of three modules:

  • The signer website itself – provides a user-friendly interface for key management and operation intents.
  • Client intent module – JS library that simplifies StellarExpertId integration and usage.
  • Server-side vault – a simple server that provides API for encrypted credentials storage and 2FA verification.

(Server-side vault storage option is temporarily disabled).

The intent library supports the following actions ("intents"):

  • signTransaction(xdr, options) – requests transaction signing (returns signed transaction envelope, can be used for multi-sig).
  • pay(destination, amount, asset_code, asset_issuer, memo, memo_type, options) – requests a payment.
  • trust(asset_code, asset_issuer, limit, options) – requests inflation pool voting.
  • inflationVote(inflationDestination, options) – requests inflation pool voting.
  • signMessage(msg) – requests arbitrary data signing.
  • verifyMessage(msg, signature) – requests arbitrary data signature verification.
  • requestAddress() – requests account public key (for basic web authentication).
  • authenticate() – requests user identity verification (for SSO login).
  • requestPersonalInfo() – requests personal info access (avatar, nickname etc).

Available transaction intent options:

  • network – stellar account network identifier ("public", "testnet") or private network passphrase.
  • horizon – the url of a Stellar Horizon server (for transactions only).
  • prepare – if set, the signer will return a signed tx envelope instead of submitting it to the Horizon server.

Formal intent data contracts can be found here.

"web+stellar" links

In order to set up this application as a signer for "web+stellar" links as described in SEP-0007, you may either use navigator.registerProtocolHandler() (works in Chrome and Firefox) or configure the protocol binding manually.

navigator.registerProtocolHandler('web+stellar', 
    'https://id.stellar.expert/confirm?encoded=%s', 
    'StellarExpertId signer')

Please note: it's a developer preview software version, do not store your real Stellar account secret keys here.

Secret key storage options

Choose security options that suit you.

Multi-login with Two-factor authorization

Allowing this feature increases security and simplify your account usage across all your devices and browsers. Your secret key is encrypted with your password in the browser and securely stored on our servers. We do not have access to your account.

Account log-in and all subsequent actions are protected with 2FA TOTP authorization.

This feature works with 2FA applications like Google Authenticator, Free OTP, or Authy.

Browser-only storage with password protection

Credentials are encrypted with your password and stored in the browser. Nobody except you can obtain access to your account.

Account log-in and all subsequent actions require your password.

Paranoid mode

StellarExpert ID never stores your credentials or any other info on our servers, nor in the browser. Nevertheless, you still can sign transactions and use other features providing your secret key to confirm all actions.

Account log-in and all subsequent actions require your secret key.

Next steps

Once the interfaces and modules are stable and documented, I'm going to add support of other security-related applications, like Ledger Nano support, StellarGuard by Paul, CosmicLink by MisterTicot etc.

Liabilities and trust

Originally this application was designed as a part of StellarExpert, but the more I think about it, the more I convince myself that it should be maintained and operated by the reliable public entity. Why would you trust some random anonymous guy from the internet?

Hence I decided to ask SDF to maintain and host the application. I'm ready to transfer the repositories, all explicit and implicit copyrights, claiming only as much as a reference in the readme/license repository file. The reasons behind this decision:

  • Safe development. All pull requests will be reviewed by SDF maintainers, and we all know that Bartek is a top-notch security specialist.
  • Trusted infrastructure. The application will be deployed and administrated by guys who support Core nodes and publicly available Horizon.
  • Trusted entity. I think we all can agree that SDF is the most trusted entity across Stellar Network as it runs the crucial part of the network and holds the largest part of all available Lumens.

If SDF itself runs the application under its own brand (say, "StellarID"), it will give green light to all developers and users. We all can be sure that guys from SDF won't modify sources to steal users' private keys and everyone will be able to participate in the process. As for me, I'll keep contributing to the project with pull-requests.

So here I'm asking for the opinion of Stellar community. If you think that such an application will be useful, I will contact SDF with this matter.

Will be glad to hear any questions and feedback.

    Cool to see you using message signing/verification.

    dzham No, it works like Google/Twitter/Facebook OAuth.
    Once you have initiated an action, a new browser window is open and the user can approve or reject the action.

    5 months later
    OrbitLens changed the title to StellarExpert ID – Single-Sign-On App and Tx Signer for Stellar Network .

    I spent almost 6 months on the development, including 3 major refactors and multiple fixes after peer security audits. And to my mind, the result was definitely worth it, because this application may gradually simplify the life of developers (one simple interface that covers all major use cases and encapsulates other providers, like Ledger Nano, StellarGuard etc), as well as end-users (safe key management and turn-key experience across all applications).

    Please check the updated project description and the demo.

    How are you doing message signatures to stop people from maliciously sending regular txs, and having people sign them?

      dzham I'm going to parse the message. If it is a valid tx xdr, the signer will return an error.

      Something like

      try {
        new Transaction(xdr)
        // a valid transaction wouldn't throw an error
        return Promise.reject(new Error('Potentially malicious message.'))
      }
      catch(e) {
        return Promise.resolve(xdr)
      }

        From Reddit:

        @doomslise:
        Cool! I was planning on developing something like this for StellarGuard -- mind if I use this for inspiration?
        Additionally, would you be open to talking about integrating StellarGuard into this, as I believe it might be complementary?

        Yeah, for sure.

        1. It will be open-source.
        2. Hopefully it will be maintained by SDF, as it's the most trusted public entity on the Network.
        3. I specifically mentioned StellarGuard integration in the article.
        4. It would be great if we could integrate all existing key management and security-related solutions like StellarGuard, CosmicLink, Ledger Nano support into one single full-featured application. It will be better tested and easier to support. And Stellar application developers will need to integrate only one micro-module with standard interface to make it accessible for all Stellar users.
        5. I hope that we all can agree on the new key management standard (e.g. SEP-0011).
        6. It doesn't mean that I will be in charge of the development. I will contribute to the project working with pool requests, the same way as any other developer.

          OrbitLens

          I really like what you're doing.

          I'm trying to do this integration job with cosmic links. I recently added transparent support for StellarGuard. Right now I'm working on integrating transparent signatures sharing.

          Recently, I made the cosmic.link website compatible with Ledger Wallets, Stellar Laboratory and future Sep-0007 wallets:

          https://cosmic.link/?setOptions&inflationDest=GCCD6AJOYZCUAQLX32ZJF2MKFFAUJ53PVCFQI3RHWKL3V47QYE2BNAUT

          I'll be happy to add support for Stellar Expert Id.

          I wrote an article that have few proposals about how to work together under a common language: Understanding Cosmic Links

          I think that in the near future every wallet will have to offer such features. Would be great to agree upon simple GET/POST scheme that everybody could implement, rather than multiplying custom solutions. The reason I favor GET request despite their lack of privacy is that it works with serverless wallets.

            MisterTicot I saw your work and was really impressed by your approach. Of course it's better to agree on an unified standard than maintain multiple solutions. Your links protocol definitely makes sense for various use-cases, in particular for situations where the initiator (wallet, exchange or any other app) doesn't know user account public key in advance.

              OrbitLens Yes. Now we'll also need a way to pass the public key, and a way to login. You're the first getting there so I hope you'll bring us some neat protocol for that ?

              dzham

              Firefly only sign the pure json string to avoid this kind of scenario.

                @OrbitLens I think i am late for this article and the idea. I wrote some similar APIs for Firefly here (in Chinese only, have not translated in English yet).
                We have created some "dapps" with these APIs.

                Now I must catch up with you. it's better to agree on an unified standard than maintain multiple solutions

                OrbitLens
                dzham
                Eno

                There are other critical things that should not be signed that easily. For example the DKIF protocol allow a tier to manage a federated server on your behalf. To guarantee that the tier can't trick you, you sign the XDR federation response and make the signer key available on your DNS.

                Now I could trick someone into signing a federation response XDR that redirect to my account. This would defeat the purpose of DKIF.

                There could be other critical piece of data that could add up over time and the last thing you want is maintaining a (likely) incomplete list of checks for them.

                Now I'm not sure if we're talking about signing data for login/authentication purpose or signing arbitrary data, like in signing messages or contracts.

                For login purpose I would rather use hash(hash(x)) like Dhzam. As you know signing a text or the hash or a text might end up having a legal value, so one have to be careful here. Maybe we should restrict heavily what we accept in input.

                If the purpose is to sign abritrary data, now that's a bit complicated. Maybe transforming the data will defeat the purpose, and signing a hash of a hash as well. If it's only about signing messages and contract you could reject anything that has no space or that is accepted by JSON.parse().

                I would separate the two things in two different operations:

                ...?login&domain=external.io&callback=dex.html&challenge=...

                ...?signData&domain=external.io&callback=enter.html&data=....

                Not sure if I'm missing something. Probably I do ?

                  Is there a design document that describes the protocol, so we can easily analyze its security? If SDF adopted this, we would probably a SEP that is specific enough to allow independent implementations.

                  It seems you are relying on informal domain separation for signed messages--basically only sign authentication messages that don't look like transactions. This is not robust to upgrades. Hence, as a first step to integrating with the Stellar ecosystem, you should request a dedicated value of EnvelopeType as a pull request on Stellar-ledger-entries.x. (I'd maybe suggest a higher number like 20 to leave us plenty of room to extend the core protocol with things like a new transaction format.)

                    MisterTicot I just checked the sources of JS SDK signing module. It looks like it's not enough to request signing of tx envelope encoded in base 64. The signature requires specifically assembled buffer with mixed in network identifier. Nevertheless, it may be an exploitable attack vector, as a potential attacker may prepare the buffer and send it in byte encoded format resulting in a correct message signature. So @dzham's implementation is safer in this case.

                    It seems to me that using keypair.sign(hash(input_message)) will cover all possible implications, including mentioned DKIF signatures and other potentially unsafe cases.

                    Another way to achieve such result without hashing is to prepend public key to the message, using it as a salt: keypair.sign(keypair.publicKey() + input_message). It mixes public key into the signature base (somewhat faster than value hashing) and effectively prevents from signing malicious transactions.