Reputation: 2067
In node.js, I want to send gmail by google api. but there are only examples of using credentials.json.
Credentials.json seems to be difficult to push github, difficult to make env, and difficult to use github action secrets.
is there any way call gmail api without credentials.json??? if is there is no way, how can i manage credentials.json??
Upvotes: 4
Views: 2336
Reputation: 3367
My recommendation is to create a file named credentials.dist.json
which replaces the value of client_secret
with the string {CLIENT_SECRET}
.
credentials.dist.json
:
{
"installed": {
"client_id": "1234tacosaredelicious5789.apps.googleusercontent.com",
"project_id": "some-outh-project",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "{CLIENT_SECRET}",
"redirect_uris": ["http://localhost"]
}
}
Commit this file to your repo. Add credentials.json
to .gitignore
to prevent it from being accidentally committed later.
Upon installing this project, have your build tooling or users run the following one-liner to recreate credentials.json
:
SECRET='THE_CLIENT_SECRET'; sed "s|{CLIENT_SECRET}|$SECRET|" credentials.dist.json > credentials.json
The value of SECRET
can be stored in a password manager, a k8s secret, an environment variable, etc.
*Note that the leading space will cause most shells to skip saving it to history.
Upvotes: 0
Reputation: 1
Instead of passing string, you can pass json object
{
installed: "web",
client_id: "<idhere>",
client_secret: "<secrethere>",
redirect_uris: ''
}
Upvotes: 0
Reputation: 531
In nodejs, I wrote code like below.
Instead of exclude credentials.json you need to offer clientId, clientSecret, refreshToken, redirectUrl as other way (ex. environment)
export class GmailService {
TOKEN_PATH: string = 'token.json';
SCOPES: string[] = ['https://www.googleapis.com/auth/gmail.send'];
refreshTokenUrl: string = 'https://oauth2.googleapis.com/token';
ACCESS_TYPE: string = 'offline';
oAuth2Client: any;
gmailClient: gmail_v1.Gmail;
constructor(private readonly configService: ConfigService) {
this.oAuth2Client = new google.auth.OAuth2(
this.configService.get(env.mailer.clientId),
this.configService.get(env.mailer.clientSecret),
this.configService.get(env.mailer.redirectUrl),
);
this.gmailClient = gmail({ version: 'v1', auth: this.oAuth2Client });
this.authorize().catch((err: Error) => {
throw err;
});
}
private static encodeMessage(msg: Buffer): string {
return Buffer.from(msg)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+&/g, '');
}
async sendMail(mail: Mail.Options): Promise<void> {
if (this.configService.get(env.environment) === 'test') return;
if (this.configService.get(env.environment) !== 'production') {
mail.to = this.configService.get(env.mailer.testTarget);
}
await this.authorize();
await this.send(mail);
}
async authorize(): Promise<void> {
// check token file exists
await fs.readFile(this.TOKEN_PATH, async (err: Error, tokenFile: any) => {
let token: Token;
if (err) {
token = await this.getNewToken(); // token file not exist
} else {
token = JSON.parse(tokenFile);
if (token.expiry_date - new Date().getTime() < 30000) {
token = await this.getNewToken(); // token was expired
}
}
this.oAuth2Client.setCredentials(token);
});
}
// refresh token
async getNewToken(): Promise<Token> {
const response: AxiosResponse = await axios.post(this.refreshTokenUrl, {
client_id: this.configService.get(env.mailer.clientId),
client_secret: this.configService.get(env.mailer.clientSecret),
grant_type: 'refresh_token',
refresh_token: this.configService.get(env.mailer.refreshToken),
});
const token: Token = response.data;
if (token.expires_in && !token.expiry_date) {
token.expiry_date = new Date().getTime() + token.expires_in * 1000;
}
await fs.writeFile(this.TOKEN_PATH, JSON.stringify(token), (err: Error) => {
if (err) throw err;
});
return token;
}
private async send(mail: Mail.Options): Promise<void> {
const mailComposer: MailComposer = new MailComposer(mail); // build mail with nodemailer
mailComposer.compile().build((err: Error, msg: Buffer) => {
if (err) throw err;
this.gmailClient.users.messages.send(
{
userId: 'me',
requestBody: {
raw: GmailService.encodeMessage(msg),
},
},
(err: Error, result: any) => {
if (err) throw err;
console.log('NODEMAILER reply from server', result.data);
},
);
});
}
}
Upvotes: 0
Reputation: 117136
In order to use Google APis you must first create a project on Google developer console. Once your project is created you will be able to enable which api you are looking at using in your project.
In order to access any data you will need to create credentials. These credentials identify your project to google and are used by your application to authorize and authenticate a user vai Oauth2.
No there is no way to use any google api accessing private user data without having a credeitnals.json file in your project.
Upvotes: 1