Jika Anda menggunakan Login dengan Google dengan aplikasi atau situs yang berkomunikasi dengan server backend, Anda mungkin perlu mengidentifikasi pengguna yang saat ini sudah login di server. Untuk melakukannya dengan aman, setelah pengguna berhasil login, kirim token ID pengguna tersebut ke server Anda menggunakan HTTPS. Kemudian, pada server, verifikasi integritas token ID dan gunakan informasi pengguna yang terdapat dalam token untuk membuat sesi atau membuat akun baru.
Mengirim token ID ke server Anda
Pertama-tama, saat pengguna login, dapatkan token ID-nya:
-
Saat mengonfigurasi Login dengan Google, panggil metode
requestIdToken
dan teruskan client ID web server Anda.// Request only the user's ID token, which can be used to identify the // user securely to your backend. This will contain the user's basic // profile (name, profile picture URL, etc) so you should not need to // make an additional call to personalize your application. GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.server_client_id)) .requestEmail() .build();
-
Saat aplikasi dimulai, periksa apakah pengguna sudah login ke aplikasi Anda menggunakan Google, di perangkat ini atau perangkat lain, dengan memanggil
silentSignIn
:GoogleSignIn.silentSignIn() .addOnCompleteListener( this, new OnCompleteListener<GoogleSignInAccount>() { @Override public void onComplete(@NonNull Task<GoogleSignInAccount> task) { handleSignInResult(task); } });
-
Jika pengguna tidak dapat login secara otomatis, tampilkan pengalaman logout seperti biasa, dengan memberi pengguna opsi untuk login. Saat pengguna login, dapatkan
GoogleSignInAccount
pengguna dalam hasil aktivitas intent login:// This task is always completed immediately, there is no need to attach an // asynchronous listener. Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task);
-
Setelah pengguna login secara otomatis atau eksplisit, dapatkan token ID dari objek
GoogleSignInAccount
:private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); String idToken = account.getIdToken(); // TODO(developer): send ID Token to server and validate updateUI(account); } catch (ApiException e) { Log.w(TAG, "handleSignInResult:error", e); updateUI(null); } }
Kemudian, kirim token ID ke server Anda dengan permintaan POST HTTPS:
HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost("https://yourbackend.example.com/tokensignin"); try { List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1); nameValuePairs.add(new BasicNameValuePair("idToken", idToken)); httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); final String responseBody = EntityUtils.toString(response.getEntity()); Log.i(TAG, "Signed in as: " + responseBody); } catch (ClientProtocolException e) { Log.e(TAG, "Error sending ID token to backend.", e); } catch (IOException e) { Log.e(TAG, "Error sending ID token to backend.", e); }
Memverifikasi integritas token ID
Setelah menerima token ID melalui HTTPS POST, Anda harus memverifikasi integritas token.
Untuk memverifikasi bahwa token valid, pastikan hal berikut kriteria terpenuhi:
- Token ID ditandatangani dengan benar oleh Google. Gunakan kunci publik Google
(tersedia di
JWK atau
format PEM)
untuk memverifikasi
tanda tangan token. Kunci-kunci ini dirotasi secara berkala; memeriksa
header
Cache-Control
dalam respons untuk menentukan kapan Anda harus mengambilnya lagi. - Nilai
aud
di token ID sama dengan salah satu nilai aplikasi Anda client ID. Pemeriksaan ini diperlukan untuk mencegah token ID yang dikeluarkan untuk aplikasi yang digunakan untuk mengakses data tentang pengguna yang sama di server backend aplikasi Anda. - Nilai
iss
di token ID sama denganaccounts.google.com
atauhttps://accounts.google.com
. - Waktu habis masa berlaku (
exp
) token ID belum berlalu. - Jika Anda perlu memvalidasi bahwa token ID tersebut mewakili jaringan Google Workspace atau Cloud
akun organisasi Anda, Anda dapat memeriksa klaim
hd
, yang menunjukkan bahwa domain pengguna. Ini harus digunakan ketika membatasi akses ke sumber daya hanya untuk anggota domain tertentu. Tidak adanya klaim ini mengindikasikan bahwa akun tersebut bukan milik Domain yang dihosting Google.
Dengan kolom email
, email_verified
, dan hd
, Anda dapat menentukan apakah
Google menghosting dan bersifat otoritatif untuk alamat email. Dalam kasus di mana Google bersifat otoritatif,
pengguna diketahui sebagai pemilik akun yang sah, dan Anda
dapat melewati {i>password<i} atau
metode-metode tantangan.
Kasus saat Google bersifat otoritatif:
email
memiliki akhiran@gmail.com
, ini adalah akun Gmail.email_verified
benar danhd
ditetapkan, ini adalah akun G Suite.
Pengguna dapat mendaftar ke Akun Google tanpa menggunakan Gmail atau G Suite. Kapan
email
tidak berisi akhiran @gmail.com
dan hd
tidak ada, Google tidak
otoritatif, dan menggunakan {i>password<i}
atau metode verifikasi lainnya disarankan untuk
pengguna. email_verified
juga bisa benar karena Google awalnya memverifikasi
pengguna saat Akun Google dibuat, namun kepemilikan pihak ketiga
akun email Anda mungkin telah berubah.
Daripada menulis kode Anda sendiri untuk melakukan langkah verifikasi ini, kami sangat
merekomendasikan penggunaan library klien Google API untuk platform Anda, atau
library JWT. Untuk pengembangan dan proses debug, Anda dapat memanggil tokeninfo
endpoint validasi.
Using a Google API Client Library
Using one of the Google API Client Libraries (e.g. Java, Node.js, PHP, Python) is the recommended way to validate Google ID tokens in a production environment.
To validate an ID token in Java, use the GoogleIdTokenVerifier object. For example:
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; ... GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) // Specify the CLIENT_ID of the app that accesses the backend: .setAudience(Collections.singletonList(CLIENT_ID)) // Or, if multiple clients access the backend: //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3)) .build(); // (Receive idTokenString by HTTPS POST) GoogleIdToken idToken = verifier.verify(idTokenString); if (idToken != null) { Payload payload = idToken.getPayload(); // Print user identifier String userId = payload.getSubject(); System.out.println("User ID: " + userId); // Get profile information from payload String email = payload.getEmail(); boolean emailVerified = Boolean.valueOf(payload.getEmailVerified()); String name = (String) payload.get("name"); String pictureUrl = (String) payload.get("picture"); String locale = (String) payload.get("locale"); String familyName = (String) payload.get("family_name"); String givenName = (String) payload.get("given_name"); // Use or store profile information // ... } else { System.out.println("Invalid ID token."); }
The GoogleIdTokenVerifier.verify()
method verifies the JWT
signature, the aud
claim, the iss
claim, and the
exp
claim.
If you need to validate that the ID token represents a Google Workspace or Cloud
organization account, you can verify the hd
claim by checking the domain name
returned by the Payload.getHostedDomain()
method. The domain of the
email
claim is insufficient to ensure that the account is managed by a domain
or organization.
To validate an ID token in Node.js, use the Google Auth Library for Node.js. Install the library:
npm install google-auth-library --save
verifyIdToken()
function. For example:
const {OAuth2Client} = require('google-auth-library'); const client = new OAuth2Client(); async function verify() { const ticket = await client.verifyIdToken({ idToken: token, audience: CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend // Or, if multiple clients access the backend: //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3] }); const payload = ticket.getPayload(); const userid = payload['sub']; // If the request specified a Google Workspace domain: // const domain = payload['hd']; } verify().catch(console.error);
The verifyIdToken
function verifies
the JWT signature, the aud
claim, the exp
claim,
and the iss
claim.
If you need to validate that the ID token represents a Google Workspace or Cloud
organization account, you can check the hd
claim, which indicates the hosted
domain of the user. This must be used when restricting access to a resource to only members
of certain domains. The absence of this claim indicates that the account does not belong to
a Google hosted domain.
To validate an ID token in PHP, use the Google API Client Library for PHP. Install the library (for example, using Composer):
composer require google/apiclient
verifyIdToken()
function. For example:
require_once 'vendor/autoload.php'; // Get $id_token via HTTPS POST. $client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend $payload = $client->verifyIdToken($id_token); if ($payload) { $userid = $payload['sub']; // If the request specified a Google Workspace domain //$domain = $payload['hd']; } else { // Invalid ID token }
The verifyIdToken
function verifies
the JWT signature, the aud
claim, the exp
claim,
and the iss
claim.
If you need to validate that the ID token represents a Google Workspace or Cloud
organization account, you can check the hd
claim, which indicates the hosted
domain of the user. This must be used when restricting access to a resource to only members
of certain domains. The absence of this claim indicates that the account does not belong to
a Google hosted domain.
To validate an ID token in Python, use the verify_oauth2_token function. For example:
from google.oauth2 import id_token from google.auth.transport import requests # (Receive token by HTTPS POST) # ... try: # Specify the CLIENT_ID of the app that accesses the backend: idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID) # Or, if multiple clients access the backend server: # idinfo = id_token.verify_oauth2_token(token, requests.Request()) # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]: # raise ValueError('Could not verify audience.') # If the request specified a Google Workspace domain # if idinfo['hd'] != DOMAIN_NAME: # raise ValueError('Wrong domain name.') # ID token is valid. Get the user's Google Account ID from the decoded token. userid = idinfo['sub'] except ValueError: # Invalid token pass
The verify_oauth2_token
function verifies the JWT
signature, the aud
claim, and the exp
claim.
You must also verify the hd
claim (if applicable) by examining the object that
verify_oauth2_token
returns. If multiple clients access the
backend server, also manually verify the aud
claim.
Memanggil endpoint tokeninfo
Cara mudah untuk memvalidasi tanda tangan token ID untuk proses debug adalah dengan
gunakan endpoint tokeninfo
. Memanggil endpoint ini melibatkan
permintaan jaringan tambahan yang melakukan sebagian besar
validasi untuk Anda saat menguji
validasi dan ekstraksi payload dalam kode Anda sendiri. Tidak cocok untuk digunakan dalam produksi
kode karena permintaan dapat terhambat atau mengalami error intermiten.
Untuk memvalidasi token ID menggunakan endpoint tokeninfo
, buat HTTPS
POST atau GET ke endpoint, dan teruskan token ID di
Parameter id_token
.
Misalnya, untuk memvalidasi token "XYZ123", buat permintaan GET berikut:
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
Jika token ditandatangani dengan benar dan iss
serta exp
klaim memiliki nilai yang diharapkan, Anda akan
mendapatkan respons HTTP 200, dengan bagian
berisi klaim token ID berformat JSON.
Berikut adalah contoh respons:
{ // These six fields are included in all Google ID Tokens. "iss": "https://accounts.google.com", "sub": "110169484474386276334", "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "iat": "1433978353", "exp": "1433981953", // These seven fields are only included when the user has granted the "profile" and // "email" OAuth scopes to the application. "email": "[email protected]", "email_verified": "true", "name" : "Test User", "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg", "given_name": "Test", "family_name": "User", "locale": "en" }
Jika perlu memvalidasi bahwa token ID mewakili akun Google Workspace, Anda dapat memeriksanya
klaim hd
, yang menunjukkan domain pengguna yang dihosting. Ini harus digunakan saat
membatasi akses ke sumber daya hanya
untuk anggota domain tertentu. Tidak adanya klaim ini
menunjukkan bahwa akun tersebut tidak termasuk dalam domain yang dihosting Google Workspace.
Membuat akun atau sesi
Setelah memverifikasi token, periksa apakah pengguna sudah ada di database pengguna Anda. Jika demikian, buat sesi yang diautentikasi untuk pengguna. Jika pengguna belum berada di database pengguna, buat record pengguna baru dari informasi dalam payload token ID, dan buat sesi untuk pengguna tersebut. Anda dapat meminta pengguna untuk memberikan informasi profil tambahan yang diperlukan saat mendeteksi pengguna yang baru dibuat di aplikasi Anda.
Mengamankan akun pengguna Anda dengan Perlindungan Lintas Akun
Jika Anda mengandalkan Google untuk memproses login pengguna, Anda akan otomatis mendapatkan manfaat dari semua fitur keamanan dan infrastruktur yang dibuat oleh Google untuk mengamankan data pengguna. Namun, seandainya Akun Google pengguna disusupi atau terjadi beberapa peristiwa keamanan signifikan lainnya, aplikasi Anda juga dapat rentan terhadap serangan. Untuk melindungi akun Anda dengan lebih baik dari peristiwa keamanan besar, gunakan Perlindungan Lintas Akun untuk menerima notifikasi keamanan dari Google. Saat menerima peristiwa ini, Anda dapat melihat perubahan penting pada keamanan Akun Google pengguna, dan Anda dapat mengambil tindakan pada layanan untuk mengamankan akun Anda.