google-api - significa - invalid_grant malformed auth code
invalid_grant tratando de obtener el token oAuth de google (14)
Sigo recibiendo un error de invalid_grant
al tratar de obtener un token oAuth de Google para conectarse a su API de contactos. Toda la información es correcta y lo he trippleado, así que me quedé perplejo.
¿Alguien sabe lo que puede estar causando este problema? Intenté configurar un ID de cliente diferente para él, pero obtuve el mismo resultado, intenté conectarme de muchas maneras diferentes, incluida la prueba de autenticación forzada, pero el mismo resultado.
Aunque esta es una vieja pregunta, parece que muchos todavía la encuentran: pasamos días enteros rastreando esto nosotros mismos.
En la especificación OAuth2, "invalid_grant" es una especie de catch-all para todos los errores relacionados con tokens inválidos / caducados / revocados (grant de autenticación o token de actualización).
Para nosotros, el problema era doble:
El usuario ha revocado activamente el acceso a nuestra aplicación
Tiene sentido, pero obtén esto: 12 horas después de la revocación, Google deja de enviar el mensaje de error en su respuesta:“error_description” : “Token has been revoked.”
Es bastante engañoso porque supondrá que el mensaje de error está ahí en todo momento, lo que no es el caso. Puede verificar si su aplicación todavía tiene acceso en la página de permisos de aplicaciones .El usuario ha restablecido / recuperado su contraseña de Google
En diciembre de 2015, Google cambió su comportamiento predeterminado para que los restablecimientos de contraseñas para usuarios que no sean de Google Apps revocarán automáticamente todas las fichas de actualización de las aplicaciones del usuario. En la revocación, el mensaje de error sigue la misma regla que en el caso anterior, por lo que solo obtendrá la "error_description" en las primeras 12 horas. No parece haber ninguna forma de saber si el usuario revocó manualmente el acceso (intencional) o si sucedió debido a un restablecimiento de contraseña (efecto secundario).
Aparte de eso, hay una miríada de otras causas potenciales que podrían desencadenar el error:
- El reloj / hora del servidor no está sincronizado
- No autorizado para el acceso fuera de línea
- Estrangulado por Google
- Uso de tokens de actualización caducados
- El usuario ha estado inactivo por 6 meses
- Utilice el correo electrónico del trabajador de servicio en lugar de la ID del cliente
- Demasiados tokens de acceso en poco tiempo
- Client SDK puede estar desactualizado
- Token de actualización incorrecto / incompleto
He escrito un breve artículo que resume cada elemento con algunas pautas de depuración para ayudar a encontrar al culpable. Espero eso ayude.
Después de considerar y probar todas las otras formas aquí, así es como resolví el problema en nodejs con el módulo googleapis
junto con el módulo de request
, que utilicé para obtener los tokens en lugar del getToken()
proporcionado:
const request = require(''request'');
//SETUP GOOGLE AUTH
var google = require(''googleapis'');
const oAuthConfigs = rootRequire(''config/oAuthConfig'')
const googleOAuthConfigs = oAuthConfigs.google
//for google OAuth: https://github.com/google/google-api-nodejs-client
var OAuth2 = google.auth.OAuth2;
var googleOAuth2Client = new OAuth2(
process.env.GOOGLE_OAUTH_CLIENT_ID || googleOAuthConfigs.clientId,
process.env.GOOGLE_OAUTH_CLIENT_SECRET || googleOAuthConfigs.clientSecret,
process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl);
/* generate a url that asks permissions for Google+ and Google Calendar scopes
https://developers.google.com/identity/protocols/googlescopes#monitoringv3*/
var googleOAuth2ClientScopes = [
''https://www.googleapis.com/auth/plus.me'',
''https://www.googleapis.com/auth/userinfo.email''
];
var googleOAuth2ClientRedirectURL = process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl;
var googleOAuth2ClientAuthUrl = googleOAuth2Client.generateAuthUrl({
access_type: ''offline'', // ''online'' (default) or ''offline'' (gets refresh_token)
scope: googleOAuth2ClientScopes // If you only need one scope you can pass it as string
});
//AFTER SETUP, THE FOLLOWING IS FOR OBTAINING TOKENS FROM THE AUTHCODE
const ci = process.env.GOOGLE_OAUTH_CLIENT_ID || googleOAuthConfigs.clientId
const cs = process.env.GOOGLE_OAUTH_CLIENT_SECRET || googleOAuthConfigs.clientSecret
const ru = process.env.GOOGLE_OAUTH_CLIENT_REDIRECT_URL || googleOAuthConfigs.callbackUrl
var oauth2Client = new OAuth2(ci, cs, ru);
var hostUrl = "https://www.googleapis.com";
hostUrl += ''/oauth2/v4/token?code='' + authCode + ''&client_id='' + ci + ''&client_secret='' + cs + ''&redirect_uri='' + ru + ''&grant_type=authorization_code'',
request.post({url: hostUrl}, function optionalCallback(err, httpResponse, data) {
// Now tokens contains an access_token and an optional refresh_token. Save them.
if(!err) {
//SUCCESS! We got the tokens
const tokens = JSON.parse(data)
oauth2Client.setCredentials(tokens);
//AUTHENTICATED PROCEED AS DESIRED.
googlePlus.people.get({ userId: ''me'', auth: oauth2Client }, function(err, response) {
// handle err and response
if(!err) {
res.status(200).json(response);
} else {
console.error("/google/exchange 1", err.message);
handleError(res, err.message, "Failed to retrieve google person");
}
});
} else {
console.log("/google/exchange 2", err.message);
handleError(res, err.message, "Failed to get access tokens", err.code);
}
});
Simplemente uso la request
para realizar la solicitud de API a través de HTTP, tal como se describe aquí: https://developers.google.com/identity/protocols/OAuth2WebServer#offline
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2.example.com/code&
grant_type=authorization_code
Es posible que deba eliminar una respuesta OAuth obsoleta / no válida.
Credit: node.js google oauth2 sample dejó de funcionar invalid_grant
Nota : Una respuesta de OAuth también será inválida si la contraseña utilizada en la autorización inicial ha sido modificada.
Si está en un entorno bash, puede usar lo siguiente para eliminar la respuesta obsoleta:
rm /Users/<username>/.credentials/<authorization.json>
Esta es una respuesta tonta, pero el problema para mí fue que no me di cuenta de que ya me habían emitido un token oAuth activo para mi usuario de google que no pude almacenar. La solución en este caso es ir a la consola de la API y restablecer el secreto del cliente.
Hay muchas otras respuestas sobre SO a este efecto, por ejemplo Restablecer secreto de cliente OAuth2: ¿Los clientes deben volver a otorgar el acceso?
Hay dos razones principales para el error de invalid_grant que debe tenerse en cuenta antes de la solicitud POST de Refresh Token y Access Token.
- El encabezado de solicitud debe contener "content-type: application / x-www-form-urlencoded"
- Su carga útil de solicitud debe estar codificada en url. Datos de formulario, no enviar como objeto json.
invalid_grant definido invalid_grant como: La concesión de autorización proporcionada (por ejemplo, código de autorización, credenciales de propietario de recurso) o token de actualización no es válido, caducado, revocado, no coincide con el URI de redirección utilizado en la solicitud de autorización o se emitió a otro cliente .
Encontré otro buen artículo, here encontrará muchas otras razones para este error.
Intente cambiar su url para solicitar
https://www.googleapis.com/oauth2/v4/token
Me encontré con el mismo problema. Para mí, lo solucioné usando la dirección de correo electrónico (la cadena que termina con ... @ developer.gserviceaccount.com) en lugar de la ID del cliente para el valor del parámetro client_id. La nomenclatura establecida por Google es confusa aquí.
Me encontré con este mismo problema a pesar de especificar el access_type
"fuera de línea" en mi solicitud según la respuesta de bonkydog. Para resumir, encontré que la solución descrita aquí funcionó para mí:
https://groups.google.com/forum/#!topic/google-analytics-data-export-api/4uNaJtquxCs
En esencia, cuando agrega un Cliente OAuth2 en la consola de su API de Google, Google le otorgará un "ID de cliente" y una "Dirección de correo electrónico" (suponiendo que seleccione "aplicación web" como tipo de cliente). Y a pesar de las convenciones de nomenclatura engañosas de Google, esperan que envíe la "Dirección de correo electrónico" como el valor del parámetro client_id
cuando acceda a sus API de OAuth2.
Esto se aplica al llamar a estas dos URL:
Tenga en cuenta que la llamada a la primera URL tendrá éxito si la llama con su "ID de cliente" en lugar de su "Dirección de correo electrónico". Sin embargo, usar el código devuelto por esa solicitud no funcionará cuando intente obtener un token de portador desde la segunda URL. En su lugar, recibirá un mensaje de error 400 y un mensaje de error no válido.
Me encontré con este problema cuando no solicité explícitamente el acceso "fuera de línea" al enviar al usuario al OAuth "¿Quieres darle permiso a esta aplicación para que toque tus cosas?" página.
Asegúrese de especificar access_type = offline en su solicitud.
Detalles aquí: https://developers.google.com/accounts/docs/OAuth2WebServer#offline
(También: creo que Google agregó esta restricción a fines de 2011. Si tiene tokens anteriores desde antes, deberá enviar a los usuarios a la página de permisos para autorizar el uso sin conexión).
Mi problema era que utilicé esta URL:
https://accounts.google.com/o/oauth2/token
Cuando debería haber usado esta URL:
https://www.googleapis.com/oauth2/v4/token
Esto estaba probando una cuenta de servicio que quería acceso sin conexión al motor de almacenamiento .
Si está utilizando la biblioteca de escritura, simplemente configure el modo fuera de línea, como bonkydog, que se sugiere aquí es el código:
OAuthService service = new ServiceBuilder().provider(Google2Api.class).apiKey(clientId).apiSecret(apiSecret)
.callback(callbackUrl).scope(SCOPE).offline(true)
.build();
Tuve el mismo mensaje de error ''invalid_grant'' y fue porque el envío de authResult [''code''] desde el lado del cliente de javascript no se recibió correctamente en el servidor.
Intente devolverlo desde el servidor para ver si es correcto y no una cadena vacía.
Utilizando un ID de cliente de Android (no client_secret) estaba recibiendo la siguiente respuesta de error:
{
"error": "invalid_grant",
"error_description": "Missing code verifier."
}
No puedo encontrar ninguna documentación para el campo ''code_verifier'', pero descubrí que si estableces valores iguales en las solicitudes de autorización y token, eliminará este error. No estoy seguro de cuál debería ser el valor previsto o si debería ser seguro. Tiene una longitud mínima (16 caracteres), pero me pareció que la configuración de null
también funciona.
Estoy usando AppAuth para la solicitud de autorización en mi cliente Android que tiene una función setCodeVerifier()
.
AuthorizationRequest authRequest = new AuthorizationRequest.Builder(
serviceConfiguration,
provider.getClientId(),
ResponseTypeValues.CODE,
provider.getRedirectUri()
)
.setScope(provider.getScope())
.setCodeVerifier(null)
.build();
Aquí hay un ejemplo de solicitud de token en el nodo:
request.post(
''https://www.googleapis.com/oauth2/v4/token'',
{ form: {
''code'': ''4/xxxxxxxxxxxxxxxxxxxx'',
''code_verifier'': null,
''client_id'': ''xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com'',
''client_secret'': null,
''redirect_uri'': ''com.domain.app:/oauth2redirect'',
''grant_type'': ''authorization_code''
} },
function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(''Success!'');
} else {
console.log(response.statusCode + '' '' + error);
}
console.log(body);
}
);
Probé y esto funciona tanto con https://www.googleapis.com/oauth2/v4/token
como con https://accounts.google.com/o/oauth2/token
.
Si está utilizando GoogleAuthorizationCodeTokenRequest
en GoogleAuthorizationCodeTokenRequest
lugar:
final GoogleAuthorizationCodeTokenRequest req = new GoogleAuthorizationCodeTokenRequest(
TRANSPORT,
JSON_FACTORY,
getClientId(),
getClientSecret(),
code,
redirectUrl
);
req.set("code_verifier", null);
GoogleTokenResponse response = req.execute();
en este sitio console.developers.google.com
esta consola de tablero selecciona tu proyecto ingresa la url del juramento. la url de devolución de llamada volverá a dirigir cuando el éxito