I want to import the data from Google Spreadsheet into Firebase Database, using Google Apps Script library access to the Firebase Database.
There is tutorial that shows how it can be accomplished, I followed these steps and my code in Google Apps Script is here:
function updateData() {
function getFirebaseService(){
return OAuth2.createService('Firebase')
// Set the endpoint URL.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scopes.
.setScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database');
}
var token = getFirebaseService().getAccessToken();
Logger.log(token);
}
This is my appsscript.json↓
{
"timeZone": "Asia/Hong_Kong",
"dependencies": {
"libraries": [{
"userSymbol": "OAuth2",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF",
"version": "33"
}, {
"userSymbol": "FirebaseApp",
"libraryId": "1hguuh4Zx72XVC1Zldm_vTtcUUKUA6iBUOoGnJUWLfqDWx5WlOJHqYkrt",
"version": "30"
}]
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/firebase.database",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/spreadsheets"]
}
Necessary oauthScopes has been added.
When I connected the Firebase , the result is 'Error: Access not granted or expired. 454'.
It's might be AccessToken expired, but after updating the latest PRIVATE_KEY and CLIENT_EMAIL, the error still show.
I have no idea about it , if someone could give me advices, I'll be grateful.
Related
I'm using GithubAuthProvider with the added scope repo to get the user's access token which is later used to access the GitHub GraphQL API (the GitHub App has the permissions for Contents and Metadata set to Read-only).
The problem is when I'm trying to list private repos. The API returns an empty array as if I don't have the required permissions. Moreover, when I try to list branches of a user's repo it returns an error of type FORBIDDEN.
Query:
query {
viewer {
repository(name: "some-repo") {
refs(refPrefix: "refs/heads/", first: 10) {
nodes {
name
}
}
}
}
}
Response:
{
"data": {
"viewer": {
"repository": {
"refs": null
}
}
},
"errors": [
{
"type": "FORBIDDEN",
"path": [
"viewer",
"repository",
"refs"
],
"extensions": {
"saml_failure": false
},
"locations": [
{
"line": 7,
"column": 7
}
],
"message": "Resource not accessible by integration"
}
]
}
What am I missing?
For GitHub GraphQL API, only scope repo may not be enough.
Following are scopes requested for reference. Authenticating with GraphQL
user
public_repo
repo
repo_deployment
repo:status
read:repo_hook
read:org
read:public_key
read:gpg_key
The API returns an empty array as if I don't have the required permissions.
I wonder whether you are query under the viewer. viewer can get the private repos he/she owned. For repos owned by other people, you can try
repository(name: "repo-name", owner: "login") {
name
}
It will return NOT_FOUND error if you don't have the required permissions.
Your query works fine for me :)
It turns out I read through the Firebase instructions too fast and created a Github App instead of an OAuth App.
It's now working as it should.
I'm implementing Apple Sign In in a React Native App.
The sample I'm using works well within the Mobile App:
Apple Sign In - React Native Firebase
Just in case the link above changes, here is the code:
import auth from '#react-native-firebase/auth';
import { appleAuth } from '#invertase/react-native-apple-authentication';
async function onAppleButtonPress() {
// Start the sign-in request
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
});
// Ensure Apple returned a user identityToken
if (!appleAuthRequestResponse.identityToken) {
throw 'Apple Sign-In failed - no identify token returned';
}
// Create a Firebase credential from the response
const { identityToken, nonce } = appleAuthRequestResponse;
const appleCredential = auth.AppleAuthProvider.credential(identityToken, nonce);
// Sign the user in with the credential
return auth().signInWithCredential(appleCredential);
}
In my backend Apps are only authorized to make calls if they use Firebase Access Tokens.
To get this to work, I am using the Google/Firebase REST API signInWithIdp. This works perfectly well for Twitter/Facebook/Google, but it doesn't for Apple.
What I/m doing is to use the Apple identityToken obtained here:
const { identityToken, nonce } = appleAuthRequestResponse;
And I make this call:
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key={key}
BODY:
{
"postBody":"id_token={identityToken}&providerId=apple.com",
"requestUri":"http://localhost",
"returnSecureToken": true
}
but I get:
{
"error": {
"code": 400,
"message": "MISSING_OR_INVALID_NONCE : Duplicate credential received. Please try again with a new credential.",
"errors": [
{
"message": "MISSING_OR_INVALID_NONCE : Duplicate credential received. Please try again with a new credential.",
"domain": "global",
"reason": "invalid"
}
]
}
}
Due to the lack of documentation I'm blocked on this one. :(
Any suggestions on how to eliminate this error are very welcome. :)
Here is the documentation to support 'Sign in with OAuth credential'. The examples it gives looks like this:
id_token=[GOOGLE_ID_TOKEN]&providerId=[google.com]
You can actually add a nonce parameter as well (which isn't documented!), for example:
id_token=ID_TOKEN&providerId=apple.com&nonce=NONCE
To figure this out, I had to use the SDK (I used iOS) and make the request. I used mitmproxy to read the network, and this is what it showed when putting in dummy data:
I've been loosely following the boilerplate in quickstart-js. I don't want to rely on Chrome's identify provider but rather want users to be able to sign in to my extension with their Google login using a popup so I haven't gone through the song and dance of requesting identity permissions in my manifest.json. My file is as follows:
{
"manifest_version": 2,
"name": "Firebase Auth in Chrome Extension Sample",
"description": "This sample shows how to authorize Firebase in a Chrome extension using a Google account.",
"version": "2.1",
"icons": {
"128": "firebase.png"
},
"browser_action": {
"default_icon": "firebase.png",
"default_popup": "credentials.html"
},
"background": {
"page": "background.html"
},
"content_security_policy":"script-src 'self' https://apis.google.com https://www.gstatic.com/ https://*.firebaseio.com https://www.googleapis.com; object-src 'self'"
}
I have baseline code that is similar to what's in quickstart-js. The relevant portion in my credentials.js is here:
/**
* Start the auth flow and authorizes to Firebase.
*/
async function startAuth() {
await firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION);
const provider = new firebase.auth.GoogleAuthProvider();
const res = await firebase.auth().signInWithPopup(provider);
}
// Starts the sign-in process.
function startSignIn() {
document.getElementById('quickstart-button').disabled = true;
if (firebase.auth().currentUser) {
firebase.auth().signOut();
} else {
startAuth();
}
}
window.onload = function() {
initApp();
};
This seems like it should work but constantly receive the following message:
Uncaught (in promise) Error: This chrome extension ID (chrome-extension://cckmbfklaloiadcphibealkhpncehpng) is not authorized to run this operation. Add it to the OAuth redirect domains list in the Firebase console -> Auth section -> Sign in method tab.
According to the official docs, I should be able to whitelist my Chrome extension's ID in the Firebase control panel. I'm repeatedly given a success message but the extension "url" doesn't show up in my list of Authorized Domains and I keep getting the error message.
Is there somewhere else I need to add the Chrome Extension url?
This seems to have just been a regression. I reached out to Firebase support, got an answer a few days later, but by that point the bug was fixed.
I want to send a welcome message (SMS) to phone number of my app's user when they will sign up using their phone number. I couldn't find official documentation for this particular task.
Amazon lets you do this. Assuming you're using Cognito for sign-up, you'll want to use the post-confirmation Cognito lambda trigger.
Set up your SNS account via the AWS Console, to send SMS messages. Send yourself a test message via the console.
Run amplify auth update
When it gets to the question Do you want to configure Lambda Triggers for Cognito?, answer Yes and choose the Post Confirmation trigger
You need to grant SNS (SMS) permissions to the lambda. Update the PostConfirmation-cloudformation-template.json file to add a new statement under Resources.lambdaexecutionpolicy.Properties.PolicyDocument.Statement:
{
"Resources": {
"lambdaexecutionpolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": "sns:*",
"Resource": "*"
}
]
...
}
...
}
...
}
...
}
...
}
Use this code for the trigger:
var aws = require('aws-sdk');
var sms = new aws.SNS();
exports.handler = (event, context, callback) => {
console.log(event);
if (event.request.userAttributes.phone_number) {
sendSMS(event.request.userAttributes.phone_number, "Congratulations " + event.userName + ", you have been confirmed: ", function (status) {
// Return to Amazon Cognito
callback(null, event);
});
} else {
// Nothing to do, the user's phone number is unknown
callback(null, event);
}
};
function sendSMS(to, message, completedCallback) {
const params = {
Message: message, /* required */
PhoneNumber: to
};
sns.publish(params, function (err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
} else {
console.log(data);
}
completedCallback("SMS Sent");
})
};
Not sure if sending SMS is a service, Amazon Amplify provides.
But you could use a service like Twilio to send SMS (and much more) to phones.
AWS Amplify can help you setting up SMS, Email and Push notifications to your users by integrating with Amazon Pinpoint. Take a look at the documentation here: https://aws-amplify.github.io/docs/js/push-notifications.
Amazon Pinpoint allows you to create user segmentation, message templates, campaigns (with A/B testing and canary as well), Journeys (for email only so far), and so many more other things. You can integrate it and configure it using AWS Amplify, but some of those features I've mentioned are still not supported by AWS Amplify and you will have to either use the AWS Console to configure or use the AWS SDK to integrate with your app. You can leverage the AWS Amplify Auth module in order to get a valid Cognito token which will allow you to interact with Amazon Pinpoint directly.
I am trying to query the Google Analytics Reporting API from a node.js application.
I think I have set up everything correctly on the google-side of things including a service account, but I must be missing a piece.
My application successfully sends usage-data to Google, I can see it come in in the realtime view. I can also query the data using the interactive API explorer.
In my node.js code I authenticate with the API at server startup like so:
var googleapis_key = require('./config/google-api-key.json');
var googleapis = require('googleapis');
var googleapis_jwtClient = new googleapis.auth.JWT(
googleapis_key.client_email,
null,
googleapis_key.private_key,
["https://www.googleapis.com/auth/analytics.readonly"],
null);
var googleapis_analyticsreporting = googleapis.analyticsreporting('v4');
googleapis_jwtClient.authorize(function(err, tokens) {
if (err) {
lStartup.error(err);
lStartup.error("Could not authenticate with google API. Analytics not available.");
} else {
lStartup.info("Successfully authenticated with google service-account.");
lStartup.debug(googleapis_jwtClient.credentials);
}
});
(where lStartup is a log4js logger). I get a positive response back from Google, err is not set and the credentials logged to the console look convincing.
Then later when the relevant client request comes in my server tries to ask google for the data:
var reportingrequests = {
"reportRequests": [
{
"viewID": "138122972",
"dateRanges": [{"startDate": "7daysAgo", "endDate": "yesterday"}],
"metrics": [{"expression": "ga:users"}]
}
]
};
logger.debug(JSON.stringify(reportingrequests));
googleapis_analyticsreporting.reports.batchGet(
{
"resource": reportingrequests,
"auth": googleapis_jwtClient,
},
function(err, response) {
if (err) {
// Failure. Log and report to the client.
console.error("Could not query the Google Analytics reporting API");
console.error(err);
res.writeHead(500, "Internal server error. (Google analytics:" + err + ")");
res.end(JSON.stringify(err));
} else {
// Success, just serve googles result to the client.
res.end(JSON.stringify(response));
}
}
);
The response is an error
[ { message: 'Invalid JSON payload received. Unknown name "view_id" at \'report_requests[0]\': Cannot find field.',
domain: 'global',
reason: 'badRequest' } ] }
What is it trying to tell me here? I do not have properties named view_id or report_requests in my JSON. Although they look suspiciously like mine de-camelcased.
I hate self-answering, but I love solutions!
"viewID": "138122972",
should be
"viewId": "138122972",
Note the lowercase "d".
Ironically the clue to this is in the camelCase to snake_case-conversion. If the parameter name was "viewID" it would propably have been snake_cased to "view_i_d", which is not what is in the error message.
I feel stupid, but also happy to be able to go on.