백엔드 서버와 통신하는 앱 또는 사이트에서 Google 로그인을 사용하는 경우 서버에 현재 로그인한 사용자를 식별해야 할 수 있습니다. 이를 위해 사용자가 성공적으로 로그인한 후에 HTTPS를 사용하여 사용자의 ID 토큰을 서버로 전송합니다. 그런 다음 서버에서 ID 토큰의 무결성을 확인하고 토큰에 포함된 사용자 정보를 사용하여 세션을 설정하거나 새 계정을 만듭니다.
서버에 ID 토큰 전송
사용자가 정상적으로 로그인한 후에 다음과 같이 사용자의 ID 토큰을 가져옵니다.
Swift
GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in guard error == nil else { return } guard let signInResult = signInResult else { return } signInResult.user.refreshTokensIfNeeded { user, error in guard error == nil else { return } guard let user = user else { return } let idToken = user.idToken // Send ID token to backend (example below). } }
Objective-C
[GIDSignIn.sharedInstance signInWithPresentingViewController:self completion:^(GIDSignInResult * _Nullable signInResult, NSError * _Nullable error) { if (error) { return; } if (signInResult == nil) { return; } [signInResult.user refreshTokensIfNeededWithCompletion:^(GIDGoogleUser * _Nullable user, NSError * _Nullable error) { if (error) { return; } if (user == nil) { return; } NSString *idToken = user.idToken; // Send ID token to backend (example below). }]; }];
그런 다음 HTTPS POST 요청을 사용하여 서버에 ID 토큰을 전송합니다.
Swift
func tokenSignInExample(idToken: String) { guard let authData = try? JSONEncoder().encode(["idToken": idToken]) else { return } let url = URL(string: "https://yourbackend.example.com/tokensignin")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let task = URLSession.shared.uploadTask(with: request, from: authData) { data, response, error in // Handle response from your backend. } task.resume() }
Objective-C
NSString *signinEndpoint = @"https://yourbackend.example.com/tokensignin"; NSDictionary *params = @{@"idtoken": idToken}; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:signinEndpoint]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPMethod:@"POST"]; [request setHTTPBody:[self httpBodyForParamsDictionary:params]]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if (error) { NSLog(@"Error: %@", error.localizedDescription); } else { NSLog(@"Signed in as %@", data.bytes); } }];
ID 토큰의 무결성 확인
HTTPS POST로 ID 토큰을 받은 후에는 토큰의 무결성을 확인해야 합니다.
To verify that the token is valid, ensure that the following criteria are satisfied:
- The ID token is properly signed by Google. Use Google's public keys
(available in
JWK or
PEM format)
to verify the token's signature. These keys are regularly rotated; examine
the
Cache-Control
header in the response to determine when you should retrieve them again. - The value of
aud
in the ID token is equal to one of your app's client IDs. This check is necessary to prevent ID tokens issued to a malicious app being used to access data about the same user on your app's backend server. - The value of
iss
in the ID token is equal toaccounts.google.com
orhttps://accounts.google.com
. - The expiry time (
exp
) of the ID token has not passed. - If you want to restrict access to only members of your G Suite domain,
verify that the ID token has an
hd
claim that matches your G Suite domain name.
Rather than writing your own code to perform these verification steps, we strongly
recommend using a Google API client library for your platform, or a general-purpose
JWT library. For development and debugging, you can call our tokeninfo
validation endpoint.
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 want to restrict access to only members of your G Suite domain,
also verify the hd
claim by checking the domain name
returned by the Payload.getHostedDomain()
method.
To validate an ID token in Node.js, use the Google Auth Library for Node.js. Install the library:
npm install google-auth-library --saveThen, call the
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 request specified a G Suite 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 want to restrict access to only members of your G Suite domain,
also verify the hd
claim matches your G Suite domain name.
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/apiclientThen, call the
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 request specified a G Suite 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 want to restrict access to only members of your G Suite domain,
also verify the hd
claim matches your G Suite domain name.
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 auth request is from a G Suite domain: # if idinfo['hd'] != GSUITE_DOMAIN_NAME: # raise ValueError('Wrong hosted domain.') # 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.
Calling the tokeninfo endpoint
An easy way to validate an ID token signature for debugging is to
use the tokeninfo
endpoint. Calling this endpoint involves an
additional network request that does most of the validation for you while you test proper
validation and payload extraction in your own code. It is not suitable for use in production
code as requests may be throttled or otherwise subject to intermittent errors.
To validate an ID token using the tokeninfo
endpoint, make an HTTPS
POST or GET request to the endpoint, and pass your ID token in the
id_token
parameter.
For example, to validate the token "XYZ123", make the following GET request:
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
If the token is properly signed and the iss
and exp
claims have the expected values, you will get a HTTP 200 response, where the body
contains the JSON-formatted ID token claims.
Here's an example response:
{ // 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": "testuser@gmail.com", "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" }
If you are a G Suite customer, you might also be interested in the hd
claim, which indicates the hosted domain of the user. This can be used to restrict access
to a resource to only members of certain domains. The absence of this claim indicates
that the user does not belong to a G Suite hosted domain.
계정 또는 세션 만들기
토큰을 확인한 후 사용자가 이미 사용자 데이터베이스에 있는지 확인합니다. 이 경우 해당 사용자의 인증된 세션을 설정합니다. 사용자가 아직 사용자 데이터베이스에 없는 경우 ID 토큰 페이로드의 정보에서 새 사용자 레코드를 만들고 사용자의 세션을 설정합니다. 앱에서 새로 생성된 사용자를 감지할 때 사용자에게 필요한 추가 프로필 정보를 묻는 메시지를 표시할 수 있습니다.
교차 계정 보호로 사용자 계정 보호하기
사용자 로그인에 Google을 의존하면 사용자의 데이터를 보호하기 위해 Google이 구축한 모든 보안 기능과 인프라를 자동으로 활용할 수 있습니다. 하지만 드물지만 사용자의 Google 계정이 도용되거나 기타 심각한 보안 이벤트가 있는 경우 앱이 공격에 취약할 수 있습니다. 계정을 주요 보안 관련 이벤트로부터 더욱 안전하게 보호하려면 교차 계정 보호 기능을 사용하여 Google로부터 보안 알림을 받으세요. 이러한 이벤트를 수신하면 사용자 Google 계정의 보안에 대한 주요 변경사항을 파악할 수 있으며 이후 서비스에 조치를 취하여 계정을 보호할 수 있습니다.