<p><strong>Telegram Passport</strong> is a unified authorization method for services that require personal identification. Users can upload their documents once, then instantly share their data with services that require real-world ID (finance, ICOs, etc.). Telegram doesn't have access to the users' personal information thanks to end-to-end encryption.</p>
<p>This page describes the request flow that client apps must used to send the requested data to the service.</p>
<p>From the perspective of a service that requires real-world ID, the process looks like this:</p>
<ul>
<li>A user presses “Log in with Telegram” on your website or in your app.</li>
<li>You request the data you need.</li>
<li>The user accepts your privacy policy and agrees to share their data.</li>
<li>The user's Telegram app downloads and decrypts the data you requested from the end-to-end encrypted storage on Telegram.</li>
<li>If some of the data you requested is missing, the user can add it to their Telegram Passport at this point.</li>
<li>The user's app encrypts the data with your public key and sends it to you.</li>
<li>You decrypt the data, check it for errors and re-request any missing or invalid information.</li>
<li>You sign the user up for your service. Tada!</li>
</ul>
<p>See <ahref="#as-a-bot">As a bot</a> to see how to request passport data using a bot, through the MTProto API.
Look at the <ahref="/passport">Passport Manual</a> to see how to request passport data using a bot, through the simplified bot API.</p>
<p>From the perspective of a user, the process looks something like this:</p>
<ul>
<li>Your app <ahref="#receiving-requests">receives an event/intent</a> from one of the <ahref="/passport#sdk">SDKs</a>, or from a custom source.</li>
<li>The user accepts your privacy policy and agrees to share their data.</li>
<li>The user's Telegram app <ahref="/passport/encryption#fetching-and-deleting-stored-passport-data">downloads the data you requested</a> from the end-to-end encrypted storage on Telegram.</li>
<li>If some of the data you requested is missing, the user can <ahref="/passport/encryption#encryption">add it to their Telegram Passport</a> at this point.</li>
<li>The user's app encrypts the data with your public key and sends it to the service.</li>
<li>You sign the user up for your service. Tada!</li>
</ul>
<p>See <ahref="#as-a-user">As a user</a> to see how user client apps should send passport data to a service, through the MTProto API.</p>
<h3><aclass="anchor"href="#as-a-bot"id="as-a-bot"name="as-a-bot"><iclass="anchor-icon"></i></a>As a bot</h3>
<p>A simplified version of this process can be used using the bot API, for more info see the <ahref="/passport">Passport Manual</a>.</p>
<p>Using the MTProto API, the process is pretty much the same, up until the actual API calls.</p>
<blockquote>
<p>Note that all binary fields are in raw binary format, unlike in the bot API where they are base64-encoded</p>
</blockquote>
<h4><aclass="anchor"href="#setting-up-telegram-passport"id="setting-up-telegram-passport"name="setting-up-telegram-passport"><iclass="anchor-icon"></i></a>Setting Up Telegram Passport</h4>
<p><ahref="/passport#setting-up-telegram-passport">As per the bot API</a>.</p>
<p>When the user confirms your request by pressing the "Authorize" button, the MTProto API sends an <ahref="/constructor/updateNewMessage">updateNewMessage</a> from the user, with a <ahref="/constructor/messageService">messageService</a> constructor, containing a <ahref="/constructor/messageActionSecureValuesSentMe">messageActionSecureValuesSentMe</a> constructor that contains the encrypted Telegram Passport data.</p>
<p>To decrypt the received data, first, decrypt the credentials contained in <ahref="/constructor/secureCredentialsEncrypted">secureCredentialsEncrypted</a>.</p>
<ol>
<li>
<p>Decrypt the credentials secret ( <em>secret</em> field in <ahref="/constructor/secureCredentialsEncrypted">secureCredentialsEncrypted</a>) using your <strong>private</strong> key (set OAEP padding option, e.g. <code>OPENSSL_PKCS1_OAEP_PADDING</code> in PHP)</p>
</li>
<li>
<p>Use this secret and the credentials hash ( <em>hash</em> field in <ahref="/constructor/secureCredentialsEncrypted">secureCredentialsEncrypted</a>) to calculate <em>credentials_key</em> and <em>credentials_iv</em> as described below:</p>
<p>Decrypt the credentials data ( <em>data</em> field in <ahref="/constructor/secureCredentialsEncrypted">secureCredentialsEncrypted</a>) by AES256-CBC using these <em>credentials_key</em> and <em>credentials_iv</em>. <strong>IMPORTANT:</strong> At this step, make sure that the credentials hash is equal to <code>SHA256( credentials_data )</code></p>
</li>
<li>
<p>Credentials data is padded with 32 to 255 random padding bytes to make its length divisible by 16 bytes. The first byte contains the length of this padding (including this byte). Remove the padding to get the data.</p>
</li>
</ol>
<blockquote>
<p>Note that all hashes are raw binary data, not hexits</p>
Since decryption credentials are E2E encrypted, apps have to store the decryption credentials as JSON and not TL payloads.</p>
<p>The credentials are used as described in the <ahref="/passport#credentials">Passport Manual</a> to decrypt the files attached to the <ahref="/constructor/secureValue">secureValue</a>.
In this case, the container for the E2E encrypted data is in TL, while the encrypted data itself is in JSON.</p>
<p>Here's a list of possible <ahref="/type/SecureValueType">SecureValueTypes</a>, and the parameters that can be set/requested when using each type.</p>
<p>Data is an encrypted and padded JSON-serialized object of one of the specified JSON types, depending on the chosen <ahref="/type/SecureValueType">type</a>.</p>
<p><ahref="/passport#datacredentials">DataCredentials</a> extracted <ahref="#credentials">from the credentials</a> can then be used to decrypt encrypted data from the <em>data</em> field in <ahref="/constructor/secureData">secureData</a>.
For more info on how to decrypt the <em>data</em> field, see the <ahref="/passport#datacredentials">passport manual</a>.</p>
<p>Files (JPG format when decrypted, max. 10 MB) are downloaded chunk by chunk as described in <ahref="/api/files">files»</a>, except that instead of generating an <ahref="/constructor/inputFile">inputFileLocation</a>, an <ahref="/constructor/inputFileLocation">inputFileLocation</a> should be generated, instead.</p>
<li>The <code>id</code> field is the <code>id</code> of the <ahref="/constructor/secureFile">secureFile</a></li>
<li>The <code>access_hash</code> field is the <code>access_hash</code> of the <ahref="/constructor/secureFile">secureFile</a></li>
</ul>
<p><ahref="/passport#filecredentials">FileCredentials</a> extracted <ahref="#credentials">from the credentials</a> can then be used to decrypt downloaded encrypted data.
For more info on how to decrypt passport files, see the <ahref="/passport#filecredentials">passport manual</a>.</p>
<p>The email/phone is passed in plaintext using the respective <ahref="/type/SecurePlainData">SecurePlainData</a> constructor.
Emails and phone numbers sent using telegram passport are <em>already verified</em> as described in the <ahref="/passport/encryption#secureplaindata">passport manual</a>.</p>
<p>If the data you received contains errors, the bot can use the <ahref="/method/users.setSecureValueErrors">users.setSecureValueErrors</a> method to inform the user and <ahref="#requesting-information">request information</a> again. The user will not be able to resend the data, until all errors are fixed.</p>
<td>Unique identifier for the bot. You can get it from bot token. For example, for the bot token <code>1234567:4TT8bAc8GHUspu3ERYn-KGcvsvGB9u_n4ddy</code>, the bot id is <code>1234567</code>.</td>
<td>Bot-specified nonce. <strong>Important:</strong> For security purposes it should be a cryptographically secure unique identifier of the request. In particular, it should be long enough and it should be generated using a cryptographically secure pseudorandom number generator. You should never accept credentials with the same nonce twice.</td>
<td><strong>Deprecated</strong> parameter from Telegram Passport 1.0 that had the same function of the <code>nonce</code> parameter.<br>Services that still use a legacy version of the SDK may provide this parameter instead of the <code>nonce</code>.<br>In some cases, both the <code>nonce</code> and the <code>payload</code> parameters may be found in a URI, for backwards compatibility: in this case, the <code>nonce</code> parameter should always be used instead of <code>payload</code>.</td>
<p>This object represents a requested element, should be one of:</p>
<ul>
<li><ahref="#uripassportscopeelementoneofseveral">UriPassportScopeElementOneOfSeveral</a> - use to request any one of the documents included in the scope.</li>
<li><ahref="#uripassportscopeelementone">UriPassportScopeElementOne</a>– use to request one particular document.</li>
</ul>
<p>Passport document type identifiers are aliased with the following reduced type identifiers:</p>
<tableclass="table">
<thead>
<tr>
<th><strong>Full</strong></th>
<th><strong>Alias</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>personal_details</code></td>
<td><code>pd</code></td>
</tr>
<tr>
<td><code>passport</code></td>
<td><code>pp</code></td>
</tr>
<tr>
<td><code>driver_license</code></td>
<td><code>dl</code></td>
</tr>
<tr>
<td><code>identity_card</code></td>
<td><code>ic</code></td>
</tr>
<tr>
<td><code>internal_passport</code></td>
<td><code>ip</code></td>
</tr>
<tr>
<td><code>id_document</code></td>
<td><code>idd</code></td>
</tr>
<tr>
<td><code>address</code></td>
<td><code>ad</code></td>
</tr>
<tr>
<td><code>utility_bill</code></td>
<td><code>ub</code></td>
</tr>
<tr>
<td><code>bank_statement</code></td>
<td><code>bs</code></td>
</tr>
<tr>
<td><code>rental_agreement</code></td>
<td><code>ra</code></td>
</tr>
<tr>
<td><code>passport_registration</code></td>
<td><code>pr</code></td>
</tr>
<tr>
<td><code>temporary_registration</code></td>
<td><code>tr</code></td>
</tr>
<tr>
<td><code>address_document</code></td>
<td><code>add</code></td>
</tr>
<tr>
<td><code>phone_number</code></td>
<td><code>pn</code></td>
</tr>
<tr>
<td><code>email</code></td>
<td><code>em</code></td>
</tr>
</tbody>
</table>
<p>You can use the special type "idd" as an alias for one of "pp", "dl", "ic" and the special type "add" as an alias for one of "ub", "bs", "ra". </p>
<p>This object represents several elements one of which must be provided.</p>
<tableclass="table">
<tbody>
<tr>
<td><strong>Field</strong></td>
<td><strong>Type</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr>
<td>_</td>
<td>Array of <ahref="#uripassportscopeelementone">UriPassportScopeElementOne</a></td>
<td>List of elements one of which must be provided; must contain either several of “pp”, “dl”, “ic”, “ip” <strong>or</strong> several of “ub”, “bs”, “ra”, “pr”, “tr”</td>
</tr>
<tr>
<td>s</td>
<td>Boolean</td>
<td><em>Optional.</em> Use this parameter if you want to request a selfie with the document from this list that the user chooses to upload.</td>
</tr>
<tr>
<td>t</td>
<td>Boolean</td>
<td><em>Optional.</em> Use this parameter if you want to request a translation of the document from this list that the user chooses to upload. <strong>Note:</strong> We suggest to only request translations <em>after</em> you have received a valid document that requires one.</td>
<p>This object represents one particular element that must be provided. If no options are needed, <em>String</em> can be used instead of this object to specify the type of the element.</p>
<tableclass="table">
<tbody>
<tr>
<td><strong>Field</strong></td>
<td><strong>Type</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr>
<td>_</td>
<td>String</td>
<td>Element type. One of "pd", "pp", "dl", "ic", "ip", "ad", "ub", "bs", "ra", "pr", "tr", "pn", "em"</td>
</tr>
<tr>
<td>s</td>
<td>Boolean</td>
<td><em>Optional.</em> Use this parameter if you want to request a selfie with the document as well. Available for "pp", "dl", "ic" and "ip"</td>
</tr>
<tr>
<td>t</td>
<td>Boolean</td>
<td><em>Optional.</em> Use this parameter if you want to request a translation of the document as well. Available for "pp", "dl", "ic", "ip", "ub", "bs", "ra", "pr" and "tr". <strong>Note:</strong> We suggest to only request translations <em>after</em> you have received a valid document that requires one.</td>
</tr>
<tr>
<td>n</td>
<td>Boolean</td>
<td><em>Optional.</em> Use this parameter to request the first, last and middle name of the user in the language of the user's country of residence. Available for "pd"</td>
</tr>
</tbody>
</table>
<p>You can also use the special type "idd" as an alias for one of "pp", "dl", "ic" and the special type "add" as an alias for one of "ub", "bs", "ra". </p>
<h4><aclass="anchor"href="#setting-up-telegram-passport"id="setting-up-telegram-passport"name="setting-up-telegram-passport"><iclass="anchor-icon"></i></a>Setting up Telegram Passport</h4>
<p>The next step for the client app is to request the user's 2FA passport, and configure Telegram Passport/fetch and decrypt remotely saved Telegram Passport parameters as described in the <ahref="/passport/encryption">Encryption article»</a>.</p>
<h4><aclass="anchor"href="#fetching-the-passport-form"id="fetching-the-passport-form"name="fetching-the-passport-form"><iclass="anchor-icon"></i></a>Fetching the passport form</h4>
<p>Then, the client app passes the bot ID, scope and public key from the <ahref="#receiving-requests">passport authorization request</a> to the Telegram servers using the <ahref="/method/account.getAuthorizationForm">account.getAuthorizationForm</a> method.</p>
<p>The response will be an <ahref="/constructor/account.authorizationForm">account.authorizationForm</a> constructor, with info about the required document types, the URL of the service's privacy policy, as well as info about the bot to which the form should be sent.
If the form was already submitted at least once, the constructor will also contain a list of already submitted data, along with eventual errors. </p>
<p>The user should accept the privacy policy and proceed to fill in the required data, and the client should encrypt and upload it as described in the <ahref="/passport/encryption">Encryption article»</a>.</p>
<h4><aclass="anchor"href="#submitting-the-passport-form"id="submitting-the-passport-form"name="submitting-the-passport-form"><iclass="anchor-icon"></i></a>Submitting the passport form</h4>
<p>Once the user finishes uploading the required documents and clicks on the submit button, the client calls <ahref="/method/account.acceptAuthorization">account.acceptAuthorization</a>, submitting the documents to the bot associated to the service.</p>
<ul>
<li>As before, <code>bot_id</code>, <code>scope</code> and <code>public_key</code> are taken from the authorization request URI.</li>
<li><code>value_hashes</code> is used by the server to choose which document of which type to send to the bot: the <code>type</code> field should be set to the document type, and the <code>hash</code> field should be set to the <code>data_hash</code>/<code>file_hash</code> generated when <ahref="/passport/encryption#encryption">uploading encrypting the data»</a>.</li>
<li><code>credentials</code> contains the encrypted credentials required by the service to decrypt the sent E2E encrypted secure values: it is generated as described in <ahref="/passport/encryption#passport-credentials">Passport Credentials»</a>.</li>
<p>If any of the values of the submitted form are rejected by the service, the bot <ahref="/api/passport#fixing-errors">calls the appropriate method to set information about errors</a>.</p>
<p>The user can find out about these errors directly from the service, or, if they decide to <ahref="#receiving-requests">restart the process</a> and resend the corrected data, directly from the authorization form (<code>errors</code> field).</p></div>
</div>
</div>
</div>
<divclass="footer_wrap">
<divclass="footer_columns_wrap footer_desktop">
<divclass="footer_column footer_column_telegram">
<h5>Telegram</h5>
<divclass="footer_telegram_description"></div>
Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.