Skip to content

auth flows

Alex Grin edited this page Oct 22, 2021 · 2 revisions

Desktop Flows

Anonymous

  1. If no auth_token is present, internal-api/user/new is called by lbryinc.Lbryio.authenticate
  2. An auth_token is returned, which looks like this: 738oP8hAK71Qfexd3urfd9nyCyxPkgoG
  3. response.auth_token is kept and sent with all subsequent requests as a POST query auth_tokenparameter

Registration

  1. internal-api/user_email/new method is called with user’s email as an argument
  2. An email with a confirmation link is sent to the user
  3. Desktop starts querying internal-api/user_email/status
  4. User clicks the link in the confirmation email, calling internal-api/user_email/confirm

Passwordless Authentication (with Merging)

The passwordless authentication allows users to "login" without concern for a password. In this system the ownership of an email account replaces the password for an account. This is more secure than a password because even with a password an account can in almost all cases be reset with access to the email associated with the account.

LBRY has implemented a passwordless system that creates an auth_token for each user when an account is registered as described above.

The login process starts from a state where the user is not logged in. This is described in the anonymous section above. From this point the user logs in by providing their email address. This triggers a call to the internal-api/user_email/new api. Inside the call we check if the email exists already or not. If it does and belongs to a different account, a verification token is generated and sent to the email address as a link to click. The user has 15 minutes to click the link to prove ownership of the email. This is done by passing back the sent verification token to internal-api/user_email/confirm via the link provided in the email.

Once ownership is confirmed we now know that the anonymous user and the user associated with the email are the same person. At this point internal-apis merges the two users into one. This is a complex transaction in the database:

https://github.com/lbryio/sqlboiler/blob/master/templates/singleton/boil_queries.tpl#L23

There are some pre-merge cleanup operations performed here:

https://github.com/lbryio/internal-apis/blob/84616366561e4192e9bb45781f6412e92de43de5/app/actions/shared/merge.go#L10

Authentication

  1. On every api call that requires authentication, the auth_token that is sent with api call is used to validate permissions and constraints based on scope. The auth_token is grabbed from the db and its scope is checked. These scopes dictate permissions and constraints. If the token is a scoped token (i.i scope is not all ) then requirements of the api are validated against the permissions and constraints approved for that scope. If not approved an authentication error is returned.

LBRYweb Flows v0.1

Anonymous

  1. If no session is present, internal-api’s internal-api/user/new is called
  2. Lbryweb forwards the call to internal-apis and returns back the full API response, saving auth_token for the current client session

Registration

  1. UI submits user credentials (email/password) to lbryweb
  2. lbryweb calls internal-api/user_2fa/newwith user’s email and password
  3. internal-apis send the confirmation email, including a link to the lbryweb confirmation address instead of lbry.com.
  4. UI starts querying internal-api/user_email/status
  5. User clicks the link in the confirmation email, calling lbryweb/confirm, which forwards the data to internal-api/user_email/confirmand marks user as registered in the lbryweb database in case of a successful response

Authentication

  1. UI submits user credentials (email/password) to lbryweb/user/auth .
  2. lbryweb calls internal-api/user_2fa/new providing user credentials.
  3. In case of successful password authentication, UI starts querying internal-apis/user_email/status and an email sent with a link to lbryweb.
  4. User clicks the link in the confirmation email, calling lbryweb/user/2fa_auth , which forwards the data to internal-apis/user_email/confirm and marks user as authenticated in the lbryweb database in case of a successful response.

Lbryweb/Internal-API Authentication Workflow

  1. Certain APIs will be protected by 2FA. For example wallet apis. A new global parameter for the password will be passed via the respective apis. If these APIs have a 2FA constraint, then it will need to pass the constraint. This constraint requires the primary email to be verified as well as the password to be authenticated.

List of internal-api endpoints to be implemented

  1. internal-api/user_2fa/new

Open Questions

  1. What do we do about the password resets? This could be solved with the signal SDK which allows for asynchronous key exchange. Since we are dealing with wallet data we want any password reset to be secure. The device which creates the password should create a key pair and pass the public key along with the password which internal-apis stores on init. This public key proves we are talking with with the device we created the password on. It also allows us to accept a signed password reset request without relying solely on email. This private key can be asynchronously exchanged with the other devices so the password reset can come from any registered device.

LBRYTV Flows v0.2

Anonymous

  1. If no session is present UI calls internal-api/user/new and auth_token is retrieved
  2. UI forwards auth_token to lbryweb, a user record is created and an account is registered with the SDK

Registration

  1. internal-api/user_email/new method is called with user’s email as an argument
  2. An email with a confirmation link is sent to the user
  3. UI starts querying internal-api/user_email/status
  4. User clicks the link in the confirmation email, calling internal-api/user_email/confirm
  5. UI sends auth_token to lbryweb, a user is marked as registered

lbrytv Authentication Spec