I'm trying to fetch/read messages from gmail. The approach I'm using is server-to-server. My application runs on nodejs. My code look something like this:
var googleapis = require('googleapis'),
JWT = googleapis.auth.JWT;
var serviceEmail = '[email protected]';
var serviceKeyFile = __dirname + '/key.pem';
var subject = '';
var authClient = new JWT(
serviceEmail,
serviceKeyFile,
null,
['https://www.googleapis.com/auth/gmail.modify'],
subject
);
authClient.authorize(function (err, tokens) {
if (err) {
console.log(err);
return;
}
console.log(tokens);
var gmail = googleapis.gmail({ auth: authClient, version: 'v1' });
var emails = gmail.users.messages.list({
includeSpamTrash: false,
maxResults: 5,
q: "",
userId: "[email protected]"
}, function (err, results) {
console.log(err);
console.log(results);
});
});
I can see that the token si there and it look like:
{ access_token: 'lettersandnumbers-etc',
token_type: 'Bearer',
expiry_date: 1427231278000,
refresh_token: 'jwt-placeholder' }
But I got this error.
{ [Error: Backend Error] code: 500 }
null
If I change subject='[email protected]' I got
{ error: 'unauthorized_client',
error_description: 'Unauthorized client or scope in request.' }
What should I do ?
You cannot use JWT to access Gmail. You need to authenticate with the appropriate user using OAuth2.
And how can I do that in nodejs ? And where is wrote that I can't do that with JWT ?
I don't think this is what I need. What I have is an email address from where I want to get messages and show them to people that connects to my application(website). The client shouldn't do anything in order to view messages. It's like the client already has access to my emails. So whenever a client visit my website the server(nodejs) makes a request to googleapi(gmail-api) and fetch all my messages from inbox.
I'm sorry, I don't understand. If you want to read the emails of Gmail accounts, you need to authenticate with OAuth2. See here for more information on how to authenticate with Gmail: https://developers.google.com/gmail/api/auth/about-auth
I want that authentication to be done on the server side.
Like the docs say, that cannot be done as far as this library is concerned. We assume you will follow the normal practices. I believe there are past issues that discuss users implementing a "PhantomJS" server to automatically accept the Google auth form from a server (headless) context, but that's beyond the scope of our support in this library.
I used to deal with this so that I authenticated my application once using standard procedures (my application generates a request URL, I copy/paste it into browser and authorise it, then copy/paste the response code back to my application), and then using the access and refresh tokens I got from that procedure. Since my app has the authentication details, I am free to serve whatever content to any incoming user.
Hope that makes sense and helps you.:)
@Alaneor can you guide me to some code ?
Nope, I do not have any of it publicly available. What are you struggling with?
The example I linked previously should give you an authentication token and
refresh token so you never have to do it manually again as long as they
aren't revoked or lost.
On Wednesday, March 25, 2015, Robert Rossmann [email protected]
wrote:
Nope, I do not have any of it publicly available. What are you struggling
with?—
Reply to this email directly or view it on GitHub
https://github.com/google/google-api-nodejs-client/issues/399#issuecomment-85966689
.
@George02, the last parameter of JWT function should be the account you are authenticating on:
var authClient = new JWT(
serviceEmail,
serviceKeyFile,
null,
['https://www.googleapis.com/auth/gmail.modify'],
"[email protected]"
);
Also, you have to delegate domain-wide authority to the service account, like reported here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount. Make sure you have provided the correct scopes for your client id. If everything is set up correctly, it should work. I actually tried with your code on my account and everything works as expected.
(who said you can't use gmail api with JWT?)
I have following simple use case. We're writing end to end test which requires us to grab body from email.
So basically what we need is read your own email api using node.js
@geezmo Looks like we can not set delegate domain-wide authority
for regular account. It would be great if you could give example reading own email using these APIs.
@George02 - Did you get it fully working?
Is there any follow up on this issue? @exonive were you able to do it? @ryanseys the example above doesn't work any more, could you point us out in the right direction?
Stumbled upon this after finding a stack overflow post. Solved this by creating the JWT using code similar to that below. Thanks to @geezmo above, although the API is a little different now your comment combined with the stack overflow post lead me in the right direction. @ht2 dropping you in here in case we require this in the future.
import { createReadStream } from 'fs';
import { google } from 'googleapis';
import * as streamToString from 'stream-to-string';
interface Key {
readonly client_email: string;
readonly private_key: string;
}
export default async () => {
const key: Key = JSON.parse(
await streamToString(createReadStream('keyfile.json')),
);
return new google.auth.JWT({
email: key.client_email,
key: key.private_key,
scopes: [
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.readonly',
],
subject: '[email protected]',
});
};
Greetings folks! There are really two ways to do this.
If you're using G Suite, and you have access to the admin SDK, you can delegate G Suite domain wide authority to a service account. This is probably the "right way" to do things, and you can follow the domain delegation guide here:
https://developers.google.com/admin-sdk/directory/v1/guides/delegation
You can find an example of using JWT and service account credentials to make API calls here:
https://github.com/google/google-api-nodejs-client/blob/master/samples/jwt.js
If you're using a personal email account, there's another way you could do this :) You could perform a one time OAuth2 workflow, as outlined here:
https://github.com/google/google-api-nodejs-client/blob/master/samples/oauth2.js
The very first time you walk through this workflow, the oauth2Client.getToken(qs.code)
method is going to return an object with two tokens: the access_token
and the refresh_token
. The tokens can be set on any OAuth2 client, and re-used to make requests using the original user's identity. Because of that... you're going to want to be super careful with these tokens. DO NOT share them.
The access_token will expire, but as long as you have a refresh token that's fine. After you get both of these from the original request, you can set them on new OAuth2 client objects:
oauth2Client.credentials = {
access_token: 'abc123',
refresh_token: 'not-a-token';
};
For as long as the refresh_token has access (until you revoke it), you'll be able to make API calls on behalf of the user (yourself in this case).
Hopefully this helps. If y'all run into any problems, let me know!
@george02, the last parameter of JWT function should be the account you are authenticating on:
var authClient = new JWT( serviceEmail, serviceKeyFile, null, ['https://www.googleapis.com/auth/gmail.modify'], "[email protected]" );
Also, you have to delegate domain-wide authority to the service account, like reported here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount. Make sure you have provided the correct scopes for your client id. If everything is set up correctly, it should work. I actually tried with your code on my account and everything works as expected.
(who said you can't use gmail api with JWT?)
I spent 3 days trying to get service account to work with gmail API. I had to rabbit-hole deep into threads on the darkest of webs to finally find a link to this post. How to properly authenticate as a delegated service account needs to be included in the docs.
Most helpful comment
@George02, the last parameter of JWT function should be the account you are authenticating on:
Also, you have to delegate domain-wide authority to the service account, like reported here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount. Make sure you have provided the correct scopes for your client id. If everything is set up correctly, it should work. I actually tried with your code on my account and everything works as expected.
(who said you can't use gmail api with JWT?)