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:
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.
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.
First, use a console to generate a private key:
openssl genrsa 2048 > private.key
WARNING: Keep your private key SECRET!
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.
To request information stored in a Telegram Passport, use one of these SDKs:
Use the following parameters to request information with the SDK:
|bot_id||Integer||Yes||Unique identifier for the bot. You can get it from bot token. For example, for the bot token
|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.|
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.
|utility_bill||files||Array of PassportFile||Utility Bill|
|bank_statement||files||Array of PassportFile||Bank Statement|
|rental_agreement||files||Array of PassportFile||Rental Agreement|
|passport_registration||files||Array of PassportFile||Registration Page in the Internal Passport|
|temporary_registration||files||Array of PassportFile||Temporary Registration|
This object represents personal details.
|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)|
This object represents a residential address.
|street_line1||String||First line for the address|
|street_line2||String||Optional. Second line for the address|
|country_code||String||ISO 3166-1 alpha-2 country code|
|post_code||String||Address post code|
This object represents the data of an identity document.
|expiry_date||String||Optional. Date of expiry, in DD.MM.YYYY format|
This object represents a PassportFile related to a document. The file is up to 10MB in size and in the .jpg format.
Your bot can pass the following values as the scope parameter to request data:
|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|
|Request email address|
Note that all base64-encoded fields should be decoded before use.
To decrypt the received data, first, decrypt the credentials contained in EncryptedCredentials.
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 )
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 )
Note that all hashes represent as raw binary data, not hexits
Credentials is a JSON-serialized object.
|secure_data||SecureData||Credentials for encrypted data|
IMPORTANT: Make sure that the payload is the same as was passed in the request.
This object represents the credentials required to decrypt encrypted data. All fields are optional and depend on fields that were requested.
|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|
This object represents the credentials required to decrypt encrypted value. All fields are optional and depend on the type of field.
|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.|
These credentials can be used to decrypt encrypted data from the data field in EncryptedPassportData.
|data_hash||String||Checksum of encrypted data|
|secret||String||Secret of encrypted data|
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 )
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 ).
These credentials can be used to decrypt encrypted files from the front_side, reverse_side, selfie and files fields in EncryptedPassportData.
|file_hash||String||Checksum of encrypted file|
|secret||String||Secret of encrypted file|
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 )
Download the encrypted file using the getFile method.
SHA256( file_content ).
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.