2013-01-07 1 views
8

Google API (버전 google-oauth-java-client-1.12.0-beta) OAuth2 액세스 토큰을 얻지 만 다시 "invalid_grant"를 받았습니다. 참고 : 여기에 https://developers.google.com/accounts/docs/OAuth2ServiceAccount서비스 계정 흐름에 대해 Google API [google-oauth-java-client-1.12.0-beta]를 사용하여 토큰을 가져올 수 없습니다.

코드입니다 :

import com.google.api.client.auth.jsontoken.JsonWebSignature; 
import com.google.api.client.auth.jsontoken.JsonWebToken; 
import com.google.api.client.auth.jsontoken.RsaSHA256Signer; 
import com.google.api.client.auth.oauth2.TokenRequest; 
import com.google.api.client.auth.oauth2.TokenResponse; 
import com.google.api.client.http.GenericUrl; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.http.javanet.NetHttpTransport; 
import com.google.api.client.json.JsonFactory; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.client.util.Clock; 

import java.io.FileInputStream; 
import java.io.IOException; 

import java.security.GeneralSecurityException; 
import java.security.KeyStore; 
import java.security.KeyStoreException; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.UnrecoverableKeyException; 
import java.security.cert.CertificateException; 


public class TestClient 
{ 
    private static PrivateKey getPrivateKey(String keyFile, String alias, String password) 
    throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException 
    { 
    KeyStore keystore = KeyStore.getInstance("PKCS12"); 
    keystore.load(new FileInputStream(keyFile), password.toCharArray()); 
    PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray()); 

    return privateKey; 
    } 

    public static void main(String[] args) 
    throws GeneralSecurityException, IOException 
    { 
    String password = "notasecret"; 
    String alias = "privatekey"; 
    String keyFile = "<private key file>.p12"; 
    String serviceAccountScopes = "https://www.googleapis.com/auth/urlshortener"; 
    String serviceAccountUser = "[email protected]"; 
    String serviceAccountId = "<a/c id>.apps.googleusercontent.com"; 
    JsonWebSignature.Header header = new JsonWebSignature.Header(); 
    header.setAlgorithm("RS256"); 
    header.setType("JWT"); 

    JsonWebToken.Payload payload = new JsonWebToken.Payload(Clock.SYSTEM); 
    long currentTime = Clock.SYSTEM.currentTimeMillis(); 
    payload.setIssuer(serviceAccountId) 
     .setAudience("https://accounts.google.com/o/oauth2/token") 
     .setIssuedAtTimeSeconds(currentTime/1000) 
     .setExpirationTimeSeconds(currentTime/1000 + 3600) 
     .setPrincipal(serviceAccountUser); 
    payload.put("scope", serviceAccountScopes); 
    System.out.println(payload.toPrettyString()); 

    PrivateKey serviceAccountPrivateKey = getPrivateKey(keyFile, alias, password); 
    String assertion = RsaSHA256Signer.sign(serviceAccountPrivateKey, getJsonFactory(), header, payload);  
    TokenRequest request = new TokenRequest(getTransport(), getJsonFactory(), new GenericUrl(getTokenServerEncodedUrl()), "assertion");  

    request.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");  
    request.put("assertion", assertion);  
    TokenResponse resp = request.execute();  
    System.out.println("token : " + resp.getAccessToken()); 
    } 

    private static String getTokenServerEncodedUrl() 
    { 
    return "https://accounts.google.com/o/oauth2/token"; 
    } 

    private static JsonFactory getJsonFactory() 
    { 
    return new JacksonFactory(); 
    } 

    private static HttpTransport getTransport() 
    { 
    return new NetHttpTransport(); 
    } 
} 

결과 :

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request 
{ 
    "error" : "invalid_grant" 
} 
    at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:103) 
    at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:303) 
    at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:323) 

여기에 문제가 무엇입니까? 어떤 힌트라도 감사 할 것입니다.

답변

7

Google 서비스 및 Google API 클라이언트 라이브러리에서 서비스 계정을 사용할 때 다음을 통해 서비스 계정 승인을 간단히 수행 할 수있는 읽기 전용 유틸리티 클래스가 있으므로 서명을 만들고 JWT 토큰을 직접 생성 할 필요가 없습니다. OAuth 2.0.

그러나 여러 프로그래밍 언어로 자세한 설명과 코드 샘플이 포함 된 Google 드라이브 문서를 제외하고는 설명이 잘되어 있지 않습니다. 당신은 읽어야 https://developers.google.com/drive/service-accounts#google_apis_console_project_service_accounts

일부 문제를 코드로 :

  • 서비스 계정의 ID는 형식이어야합니다 : <some-id>@developer.gserviceaccount.com은 (예, 내가 이상한 대신 클라이언트 ID의 이메일을 알고있다)
  • Google Apps domain Wide delegation을 수행 할 때 principal 만 설정하지만 Gmail 계정에서는 할 수 없습니다. 물론 관리자가 액세스 권한을 부여한 도메인의 Google Apps 계정에서만 가능합니다. 설정하지 마세요. .

다음은 Java의 OAuth 2.0 w/Service 계정 코드 샘플입니다.

참고 : the URL Shortener library도 다운로드해야합니다.

/** Email of the Service Account */ 
private static final String SERVICE_ACCOUNT_EMAIL = "<some-id>@developer.gserviceaccount.com"; 

/** Path to the Service Account's Private Key file */ 
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/<public_key_fingerprint>-privatekey.p12"; 

/** 
* Build and returns a URL Shortner service object authorized with the service accounts. 
* 
* @return URL Shortner service object that is ready to make requests. 
*/ 
public static Drive getDriveService() throws GeneralSecurityException, IOException, URISyntaxException { 
    HttpTransport httpTransport = new NetHttpTransport(); 
    JacksonFactory jsonFactory = new JacksonFactory(); 
    GoogleCredential credential = new GoogleCredential.Builder() 
     .setTransport(httpTransport) 
     .setJsonFactory(jsonFactory) 
     .setServiceAccountId(SERVICE_ACCOUNT_EMAIL) 
     .setServiceAccountScopes(UrlshortenerScopes.URLSHORTENER) 
     .setServiceAccountPrivateKeyFromP12File(
      new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH)) 
     .build(); 
    Urlshortener service = new Urlshortener.Builder(httpTransport, jsonFactory, null) 
     .setHttpRequestInitializer(credential).build(); 
    return service; 
} 
+1

애드 센스로 작업 할 때 여전히이 "invalid_grant"예외가 발생합니다. 클라이언트 ID가 유효하며 범위는 AdSenseScopes.ADSENSE입니다. 애드 센스 관리 API가 활성화되었습니다. 아무 단서도 그것을 고칠 수 없다 – user12384512

+0

NodeJS 래퍼로 작업해도 큰 도움이된다. 내 문제는 응용 프로그램 전자 메일 주소 대신 내 계정 전자 메일을 사용했기 때문입니다. 감사! –

+0

굉장한 답변! Google 스프레드 시트 자바 API로 JWT 오류가 발생했습니다. 서비스 계정을 통해 Google API 서비스에 자격 증명을 가져 오는 작업 Java 코드 예제를 찾는 것이 거의 불가능했습니다 (이 스레드 제외). 답변을 반영하기 위해 자격 증명을 바꿨을 때, 이제 Google 스프레드 시트 API를 통해 비공개 사용자에게 성공적으로 요청합니다. 또한 시트를 사용하여 작업 할 때 서비스 계정의 전자 메일 주소 (다운로드 한 json 키/ID 파일)의 개인 시트 (공유 단추를 통해)의 사용 권한을 허용하는지 확인하십시오 – ganta

관련 문제