I am attempting to upload videos to YouTube using the YouTube Data API and a service account in my Node.js backend. However, I keep encountering an “Unauthorized” error. Here is a summary of what I have done so far:
Set Up Service Account:
Created a service account in the Google Cloud Console and downloaded the JSON key file.
Enabled domain-wide delegation and provided the necessary permissions in the G Suite Admin console.
Granted the following scopes: https://www.googleapis.com/auth/youtube.upload.
Backend Code:
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { google } = require('googleapis');
const credentials = require('./path/to/your/service-account-file.json');
const router = express.Router();
const scopes = ['https://www.googleapis.com/auth/youtube.upload'];
// Initialize the JWT client
const auth = new google.auth.JWT(
credentials.client_email,
null,
credentials.private_key,
scopes,
'[email protected]' // G Suite user email
);
// Function to upload a video
async function uploadVideo(req, res) {
const filePath = req.file.path;
const { fileName } = req.body;
try {
const youtube = google.youtube({
version: 'v3',
auth,
});
if (!filePath) {
return res.status(400).json({ error: 'File data not provided' });
}
// Video resource
const videoParams = {
part: 'snippet,status',
requestBody: {
snippet: {
title: req.body.title || 'Test',
description: '',
tags: [],
},
status: {
privacyStatus: 'public',
},
},
media: {
body: fs.createReadStream(filePath),
},
};
// Execute the request to upload the video
const response = await youtube.videos.insert(videoParams, {
onUploadProgress: (evt) => {
const progress = (evt.bytesRead / videoParams.media.body._readableState.length) * 100;
console.log(`${Math.round(progress)}% uploaded`);
},
});
console.log('Video uploaded:', response.data);
const videoUrl = `https://www.youtube.com/watch?v=${response.data.id}`;
// Send response with video URL
res.status(200).json({ message: 'Video uploaded successfully', videoUrl });
} catch (error) {
console.error('Error uploading video:', error);
res.status(500).json({ error: 'Failed to upload video', message: error.message });
}
}
const storage = multer.diskStorage({
destination: 'uploads',
filename: function (req, file, callback) {
callback(null, `${Date.now()}.mp4`);
},
});
const upload = multer({
storage,
limits: { fileSize: 100 * 1024 * 1024 },
fileFilter: function (req, file, cb) {
const { mimetype } = file;
if (mimetype.startsWith('video/')) {
cb(null, true);
} else {
cb(new Error('Invalid file type'));
}
},
});
router.post('/youtube-upload', upload.single('file'), uploadVideo);
module.exports = router;
Frontend Code:
javascript
Copy code
const handleClick = async (e) => {
e.preventDefault();
const file = e.target.files[0];
const formData = new FormData();
formData.append('file', file);
formData.append('fileName', file.name);
if (file.type.startsWith('video/')) {
try {
const response = await fetch('/youtube-upload', {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('Failed to upload video to YouTube');
}
const data = await response.json();
console.log('YouTube upload successful', data);
// Update state with the video URL or handle success
} catch (error) {
console.error('Error uploading video to YouTube:', error.message);
// Handle error (e.g., show error message to user)
}
} else {
// Handle non-video uploads
}
}; ```
Despite these steps, I am getting the following error message:
GaxiosError: Unauthorized
I have ensured that:
The service account has the appropriate permissions.
The JWT token is correctly generated and used.
What am I missing or doing wrong? Any help would be greatly appreciated.