Telegram Passport Manual

Telegram Passport 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.

From the perspective of a service that requires real-world ID, the process looks like this:

  • A user presses “Log in with Telegram” on your website or in your app.
  • You request the data you need.
  • The user accepts your privacy policy and agrees to share their data.
  • The user's Telegram app downloads and decrypts the data you requested from the end-to-end encrypted storage on Telegram.
  • If some of the data you requested is missing, the user can add it to their Telegram Passport at this point.
  • The user's app encrypts the data with your public key and sends it to you.
  • You decrypt the data, check it for errors and re-request any missing or invalid information.
  • You sign the user up for your service. Tada!

Check out this example to see Telegram Passport in action.

To learn more about Telegram Passport from the perspective of a user, please see this blog post.

Setting Up Your Bot

To integrate Telegram Passport into your login or verification flow, you need a working Telegram bot (see this page for information on how to get one).

To request data from Telegram Passport users, your bot will need to generate a pair of encryption keys.

Generating a private key

First, use a console to generate a private key:

openssl genrsa 2048 > private.key

WARNING: Keep your private key SECRET!

Generating your public key

Then use the console to print the corresponding public key:

openssl rsa -in private.key -pubout

Use the /setpublickey command with @BotFather to connect this public key with your bot.

Privacy Policy

Add a link to your Privacy Policy by using the /setprivacypolicy command. Users will see this link when offered to authorize you to access their data.

Requesting Information

SDK

To request information stored in a Telegram Passport, use one of these SDKs:

Request Parameters

Use the following parameters to request information with the SDK:

Parameters Type Required Description
bot_id Integer Yes Unique identifier for the bot. You can get it from bot token. For example, for the bot token 1234567:4TT8bAc8GHUspu3ERYn-KGcvsvGB9u_n4ddy, the bot id is 1234567.
scope Array of String Yes List the names of fields you want to request
public_key String Yes Public key of the bot
payload String Yes Bot-specified payload. Important: 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 payload twice.

Fields

Your bot can request personal details, one type of identity document, residential address, one type of proof of address document, a phone number, or an email address.

If several types of identity documents are mentioned in the scope of the request, the user can choose which type to upload/provide. The same applies to proof of address. See also the list of data that can be requested using Telegram Passport.

NameKeyTypeDescription
personal_detailsdataPersonalDetailsPersonal Details
passportdataIdDocumentDataPassport
front_sidePassportFile
selfieOptional. PassportFile
internal_passportdataIdDocumentDataInternal Passport
front_sidePassportFile
selfieOptional. PassportFile
driver_licensedataIdDocumentDataDriver License
front_sidePassportFile
reverse_sidePassportFile
selfieOptional. PassportFile
identity_carddataIdDocumentDataIdentity Card
front_sidePassportFile
reverse_sidePassportFile
selfieOptional. PassportFile
addressdataResidentialAddressAddress
utility_billfilesArray of PassportFileUtility Bill
bank_statementfilesArray of PassportFileBank Statement
rental_agreementfilesArray of PassportFileRental Agreement
passport_registrationfilesArray of PassportFileRegistration Page in the Internal Passport
temporary_registrationfilesArray of PassportFileTemporary Registration
phone_numberStringPhone number
emailStringEmail

PersonalDetails

This object represents personal details.

Field Type Description
first_name String First Name
last_name String Last Name
birth_date String Date of birth in DD.MM.YYYY format
gender String Gender, male or female
country_code String Citizenship (ISO 3166-1 alpha-2 country code)
residence_country_code String Country of residence (ISO 3166-1 alpha-2 country code)

ResidentialAddress

This object represents a residential address.

Field Type Description
street_line1 String First line for the address
street_line2 String Optional. Second line for the address
city String City
state String Optional. State
country_code String ISO 3166-1 alpha-2 country code
post_code String Address post code

IdDocumentData

This object represents the data of an identity document.

Field Type Description
document_no String Document number
expiry_date String Optional. Date of expiry, in DD.MM.YYYY format

PassportFile

This object represents a PassportFile related to a document. The file is up to 10MB in size and in the .jpg format.

Available Data

Your bot can pass the following values as the scope parameter to request data:

Scope Description
personal_details Request personal details
passport Request personal details and a passport as one of the possible identity documents
internal_passport Request personal details and an internal passport as one of the possible identity documents
driver_license Request personal details and a driver license as one of the possible identity documents
identity_card Request personal details and an ID card as one of the possible identity documents
id_document Request personal details and an identity document of one of the main types: passport, driver_license, identity_card.
Alias to the scope passport, driver_license, identity_card
id_selfie Request a selfie with the identity document
address Request the user's residential address
utility_bill Request residential address and a utility bill as one of the possible proof of address documents
bank_statement Request residential address and a bank statement as one of the possible proof of address documents
rental_agreement Request residential address and a rental agreement as one of the possible proof of address documents
passport_registration Request residential address and a registration from internal passport as one of the possible proof of address documents
temporary_registration Request residential address and a temporary registration as one of the possible proof of address documents
address_document Request residential address and a proof of address document of one of the main types: utility_bill, bank_statement, rental_agreement.
Alias to the scope utility_bill, bank_statement, rental_agreement
phone_number Request phone number
email Request email address

Receiving information

When the user confirms your request by pressing the ‘Authorize’ button, the Bot API sends an Update with the field passport_data to the bot that contains encrypted Telegram Passport data.

Note that all base64-encoded fields should be decoded before use.

Decrypting data

To decrypt the received data, first, decrypt the credentials contained in EncryptedCredentials.

  1. Decrypt the credentials secret ( secret field in EncryptedCredentials) using your private key (set OAEP padding option, e.g. OPENSSL_PKCS1_OAEP_PADDING in PHP)
  2. Use this secret and the credentials hash ( hash field in EncryptedCredentials) to calculate credentials_key and credentials_iv as described below:

     credentials_secret_hash = SHA512( credentials_secret + credentials_hash )
     credentials_key = slice( credentials_secret_hash, 0, 32 )
     credentials_iv = slice( credentials_secret_hash, 32, 16 )
  3. Decrypt the credentials data ( data field in EncryptedCredentials) by AES256-CBC using these credentials_key and credentials_iv. IMPORTANT: At this step, make sure that the credentials hash is equal to SHA256( credentials_data )

  4. 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.

Note that all hashes represent as raw binary data, not hexits

Credentials

Credentials is a JSON-serialized object.

Field Type Description
secure_data SecureData Credentials for encrypted data
payload String Bot-specified payload

IMPORTANT: Make sure that the payload is the same as was passed in the request.

SecureData

This object represents the credentials required to decrypt encrypted data. All fields are optional and depend on fields that were requested.

Field Type Description
personal_details SecureValue Optional. Credentials for encrypted personal details
passport SecureValue Optional. Credentials for encrypted passport
internal_passport SecureValue Optional. Credentials for encrypted internal passport
driver_license SecureValue Optional. Credentials for encrypted driver license
identity_card SecureValue Optional. Credentials for encrypted ID card
address SecureValue Optional. Credentials for encrypted residential address
utility_bill SecureValue Optional. Credentials for encrypted utility bill
bank_statement SecureValue Optional. Credentials for encrypted bank statement
rental_agreement SecureValue Optional. Credentials for encrypted rental agreement
passport_registration SecureValue Optional. Credentials for encrypted registration from internal passport
temporary_registration SecureValue Optional. Credentials for encrypted temporary registration

SecureValue

This object represents the credentials required to decrypt encrypted value. All fields are optional and depend on the type of field.

Field Type Description
data DataCredentials Optional. Credentials for encrypted Telegram Passport data. Available for “personal_details”, “passport”, “driver_license”, “identity_card”, “internal_passport” and “address” types.
front_side FileCredentials Optional. Credentials for encrypted document's front side. Available for “passport”, “driver_license”, “identity_card” and “internal_passport”.
reverse_side FileCredentials Optional. Credentials for encrypted document's reverse side. Available for “driver_license” and “identity_card”.
selfie FileCredentials Optional. Credentials for encrypted selfie of the user with a document. Can be available for “passport”, “driver_license”, “identity_card” and “internal_passport”.
files Array of FileCredentials Optional. Credentials for encrypted files. Available for “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration” and “temporary_registration” types.

DataCredentials

These credentials can be used to decrypt encrypted data from the data field in EncryptedPassportData.

Field Type Description
data_hash String Checksum of encrypted data
secret String Secret of encrypted data
  1. To decrypt data, use the corresponding secret and data_hash from DataCredentials as described below:

     data_secret_hash = SHA512( data_secret + data_hash )
     data_key = slice( data_secret_hash, 0, 32 )
     data_iv = slice( data_secret_hash, 32, 16 )
  2. Use AES256-CBC with this data_key and data_iv to decrypt the data (the data field in EncryptedPassportData). IMPORTANT: At this step, make sure that data_hash from the credentials is equal to SHA256( data ).

  3. The 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 the padding (including this byte). Remove padding to get the data.
  4. The data is a JSON-serialized object of one of the following types: PersonalDetails, IdDocumentData, ResidentialAddress, depending on type.

FileCredentials

These credentials can be used to decrypt encrypted files from the front_side, reverse_side, selfie and files fields in EncryptedPassportData.

Field Type Description
file_hash String Checksum of encrypted file
secret String Secret of encrypted file
  1. To decrypt the file, use the corresponding secret and file_hash from FileCredentials as described below:

     file_secret_hash = SHA512( file_secret + file_hash )
     file_key = slice( file_secret_hash, 0, 32 )
     file_iv = slice( file_secret_hash, 32, 16 )
  2. Download the encrypted file using the getFile method.

  3. Use AES256-CBC with this file_key and file_iv to decrypt the content of the file. IMPORTANT: At this step, make sure that file_hash from the credentials is equal to SHA256( file_content ).
  4. The content of the file is padded with 32 to 255 random padding bytes to make its length divisible by 16 bytes. The first byte contains the length of the padding (including that byte). Remove padding to get the file content.

Fixing errors

If the data you received contains errors, the bot can use the setPassportDataErrors method to inform the user and request information again. The user will not be able to resend the data, until all errors are fixed.