Connect to multiple Firebase DB - firebase

My flutter app needs to connect to multiple firebase databases. the vision is that the user will start the application and will enter Firebase parameters and click "Connect".
I find the following source lines
FirebaseApp app;
Future<FirebaseApp> FBDB() async {
WidgetsFlutterBinding.ensureInitialized();
final FirebaseApp app = await FirebaseApp.configure(
name: "FB.AAA.com", // "package_name"
options: const FirebaseOptions(
googleAppID: "1:79046:android:2fb2895a41bde78da062d",
// "mobilesdk_app_id"
gcmSenderID: "???",
//"project_number":
apiKey: "AIzamVHoX0C_zimD3UhUITF4ml7Be4fsI",
// "api_key": [ { "current_key"
projectID: "fb-b64d", //"project_id"
),
);
}
The Google Services file is (changed the data):
{
"project_info": {
"project_number": "123",
"firebase_url": "https://fb-b64d.firebaseio.com",
"project_id": "fb-b64d",
"storage_bucket": "fb-b64d.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:79046:android:2fb2895a41bde78da062d",
"android_client_info": {
"package_name": "FB.AAA.com"
}
},
"oauth_client": [
{
"client_id": "123-5555.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzamVHoX0C_zimD3UhUITF4ml7Be4fsI"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "793081656-5555.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
The result of the source code above is null (the object was not created) so my questions are:
Did I take the right parameters from the google Json file to the source code above? what should be in the gcmSenderID?
what is the next step? how should I receive the
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance
In order to start query the DB?

If you want to get a Firebase service for a specific FirebaseApp instance, you pass that app into the service's constructor or call a factory method.
For example:
FirebaseDatabase(app: this.app).reference();
For for auth:
FirebaseAuth.fromApp(app)

Related

Next Auth Credentials Provider - SignIn() and Mapping to my API Dto

I am using Next.js and Next Auth to talk to my backend C# ASP.NET API.
My API's response is the following DTO:
{
"data": {
"accessToken": "string",
"refreshToken": "string",
"email": "user#example.com",
"username": "string",
"roles": [
"string"
]
},
"success": true,
"message": "string"
}
I am having a hard time getting that info into the next auth session so that I can grab it with useSession().
I'd also like to be able to display the API "message" to the user in the login form. Incase their account is locked or whatever.
This is what I have:
[...nextauth].js
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { API_URL } from "#/constants";
export const authOptions = {
// Configure one or more authentication providers
providers: [
// Add Your Providers Here
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const { usernme, password } = credentials;
const body = JSON.stringify({
username,
password,
});
// Login request to our API.
const res = await fetch(`${API_URL}/Login`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
},
body: body,
});
const data = await res.json();
// Our API's response contains
/*
{
"data": {
"accessToken": "string",
"refreshToken": "string",
"email": "user#example.com",
"username": "string",
"roles": [
"string"
]
},
"success": true,
"message": "string"
}
*/
const user = {
success: data.success,
message: data.message,
email: data.data.email,
username: data.data.username,
accessToken: data.data.accessToken,
refreshToken: data.data.refreshToken,
roles: data.data.roles,
};
// EVERYTHING TO HERE IS GOOD!
// I CAN GET THE user OBJECT FILLED.
if (res.ok && user) {
return user; //<---- is this actually returning the full user object to the session?
} else {
return null;
}
},
}),
],
pages: { signIn: "/login" },
};
export default NextAuth(authOptions);
Navbar Links:
<Nav.Link as={Link} href='/login' onClick={() => signIn()}>Login</Nav.Link>
<Nav.Link as={Link} href='/signout' onClick={() => signOut({callbackUrl: '/'})}>Signout</Nav.Link>
Login form:
// Get data from the form.
const nextAuthSettings = {
username: event.target.username.value,
password: event.target.password.value,
redirect: true,
callbackUrl: "/dashboard",
};
// Send the form data to Next Auth
const result = await signIn("credentials", nextAuthSettings);
// Error Handling
// THIS DOES NOT WORK
// I don't think signIn() returns a copy of the user object unfortunately...
if (!result.success) {
// Display the API Error Message On The Page
setErrorMsg(result.message);
}
And then in various pages, when I want to access the user object I am doing this :
import { useSession } from "next-auth/react";
const { data: session } = useSession();
// This only shows the email
<span>{session?.user.email}</span>;
// It looks like a JWT or something when I console log it
{
"user": {
"email": "users#email.com"
},
"expires": "2023-03-16T12:39:28.120Z"
}
Any help appreciated!
I need to be able to access the user object my API is returning throughout my app.
At the moment I'm just getting this session.user.email and nothing else ??
it's like I am not mapping the API's response to whatever Next Auth wants me to create...
you have to use callbacks :
callbacks: {
async jwt({ user, token }) {
// update token from user
if (user) {
token.user = user;
}
// return final_token
return token;
},
async session({ session, token }) {
// update session from token
session.user = token.user;
return session;
},
},
Now you can access your session with useSession() and your token with getToken()

Fauna returning 'unauthorized' when using Auth0 as a third party access provider

I am trying to integrate Fauna and Auth0 into my Vue 3 app.
To achieve that I am following this Auth0 guide and this youtube video.
In short, I have configured Auth0 as a Provider inside Fauna. And I am sending the Auth0 generated JWT token as the Fauna secret. Fauna should then decode the JWT and give access to the call.
To test it out my code fetches some dummy "products" data from Fauna and prints it to the console.
But when I make the call it returns as unauthorized.
What am I doing wrong?
Here is the script inside my Vue component that is making the call:
import { defineComponent, inject } from "vue";
import { query as q, Client } from "faunadb";
export default defineComponent({
name: "Api",
setup() {
let apiMessage = null;
let executed = false;
const auth = inject("Auth");
const callApi = async () => {
const accessToken = await auth.getTokenSilently();
console.log(accessToken);
try {
const client = new Client({ secret: accessToken });
const { Paginate, Documents, Collection } = q;
const data = await client.query(
Paginate(Documents(Collection("products")))
);
console.log(data);
apiMessage = data;
executed = true;
} catch (e) {
console.log(e);
apiMessage = `Error: the server responded with '${e.response.status}: ${e.response.statusText}'`;
}
};
return {
callApi,
};
},
});
Here is a copy of the unauthorized response object that is returned:
{
"name": "Unauthorized",
"message": "unauthorized",
"description": "Unauthorized",
"requestResult": {
"method": "POST",
"path": "",
"query": null,
"requestRaw": "{\"paginate\":{\"documents\":{\"collection\":\"products\"}}}",
"requestContent": {
"raw": {
"paginate": {
"raw": {
"documents": {
"raw": {
"collection": "products"
}
}
}
}
}
},
"responseRaw": "{\"errors\":[{\"code\":\"unauthorized\",\"description\":\"Unauthorized\"}]}",
"responseContent": {
"errors": [
{
"code": "unauthorized",
"description": "Unauthorized"
}
]
},
"statusCode": 401,
"responseHeaders": {
"content-length": "65",
"content-type": "application/json;charset=utf-8",
"x-txn-time": "1634006015704445"
},
"startTime": 1634006014934,
"endTime": 1634006015885
}
}
Figured it out.
The client has to be initiated with some other values, most importantly is the domain value.
var client = new faunadb.Client({
secret: 'YOUR_FAUNA_SECRET',
domain: 'db.fauna.com',
// NOTE: Use the correct domain for your database's Region Group.
port: 443,
scheme: 'https',
})

What are the contents of RemoteMessage of Firebase?

https://blog.logrocket.com/flutter-push-notifications-with-firebase-cloud-messaging/
// For handling the received notifications
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// Parse the message received
PushNotification notification = PushNotification(
title: message.notification?.title,
body: message.notification?.body,
);
As we can see, notification is one field in RemoteMessage structure.
and here: https://pub.dev/packages/firebase_messaging/example
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
messageId is another field in RemoteMessage.
What other fields are in this RemoteMessage structure? I tried to find its API but failed.
Can we override it and fill our own fields?
Here is the structure of RemoteMessage. You can add your custom data to the data property of it.
const RemoteMessage(
{this.senderId,
this.category,
this.collapseKey,
this.contentAvailable = false,
this.data = const <String, dynamic>{},
this.from,
this.messageId,
this.messageType,
this.mutableContent = false,
this.notification,
this.sentTime,
this.threadId,
this.ttl});
A usual notification payload when send from the backend/cloud functions looks like this:
const payload = {
notification: {
title: title,
body: message,
},
data: {
uid,
},
webpush: {
notification: {
icon: photoURL,
},
},
android: {
notification: {
image: photoURL,
},
},
apns: {
payload: {
aps: {
"mutable-content": 1,
},
},
fcm_options: {
image: photoURL,
},
},
};

Google Firebase Function Firebase auth onCreate event handler - failed to configure trigger

I am trying to add a Firebase Authentication onCreate user event handler to insert user into Google Cloud SQL database. I got it to work successfully locally with the database public IP, and it successfully adds rows to the SQL database.
I ran firebase deploy -P gircapp2 and this is what I got from the google cloud function logs:
{
"protoPayload": {
"#type": "type.googleapis.com/google.cloud.audit.AuditLog",
"status": {
"code": 13,
"message": "Failed to configure trigger providers/firebase.auth/eventTypes/user.create#firebaseauth.googleapis.com (__gcf__.us-central1.createGircUser)"
},
"authenticationInfo": {
"principalEmail": "gircapptest#gmail.com"
},
"serviceName": "cloudfunctions.googleapis.com",
"methodName": "google.cloud.functions.v1.CloudFunctionsService.UpdateFunction",
"resourceName": "projects/gircapp2/locations/us-central1/functions/createGircUser"
},
"insertId": "46dje7cgk6",
"resource": {
"type": "cloud_function",
"labels": {
"function_name": "createGircUser",
"region": "us-central1",
"project_id": "gircapp2"
}
},
"timestamp": "2021-02-02T19:01:54.537912Z",
"severity": "ERROR",
"logName": "projects/gircapp2/logs/cloudaudit.googleapis.com%2Factivity",
"operation": {
"id": "operations/Z2lyY2FwcDIvdXMtY2VudHJhbDEvY3JlYXRlR2lyY1VzZXIvQU82VHdMQkROTUE",
"producer": "cloudfunctions.googleapis.com",
"last": true
},
"receiveTimestamp": "2021-02-02T19:01:54.579884326Z"
}
Here is my index.js, which works locally and updates successfully google cloud SQL database:
const functions = require("firebase-functions");
const { Sequelize, Model, DataTypes } = require('sequelize')
const {SecretManagerServiceClient} = require('#google-cloud/secret-manager')
var password = ""
const name = 'projects/gircapp2/secrets/postgrespassword/versions/latest';
// Instantiates a client
const client = new SecretManagerServiceClient();
async function accessSecretVersion() {
const [version] = await client.accessSecretVersion({
name: name,
});
// Extract the payload as a string.
const payload = version.payload.data.toString();
password = payload
}
// run this in google functions shell emulator to make a user:
// firebase functions:shell
// firebase > createGircUser({uid: "654321"})
class User extends Model {}
exports.createGircUser = functions.auth.user().onCreate((firebaseuser) => {
(async () => {
const user = 'postgres'
const host = 'gircapp2:us-central1:gircpostgres'
const database = 'postgres'
const port = '5432'
await accessSecretVersion();
const sequelize = await new Sequelize(database, user, password, {
host,
port,
dialect: 'postgres',
logging: false
})
await User.init({
userId: {
type: DataTypes.STRING
},
name: {
type: DataTypes.STRING
},
email: {
type: DataTypes.STRING
},
speciality: {
type: DataTypes.STRING
},
degree: {
type: DataTypes.STRING
},
verified: {
type: DataTypes.BOOLEAN
}
}, {
sequelize,
modelName: "user",
timestamps: true,
})
const userId = firebaseuser.uid
await User.sync({force: false}).then(() => {
// users table created
return User.create({
userId: userId,
verified: false,
});
});
})()
})
It is possible that Firebase Auth is not yet enabled on your project because you are passing uid through a test environment to trigger the event instead of creating a new email on Firebase Console.
Fix it by going to Firebase Console > Firebase Authentication and set up Sign-In method. On your case, you can enable email or a federated identity provider (ex. Google):
Afterwards, redeploy your function then add user on the Firebase Console.
As an addition, when trying to connect to a Cloud SQL instance using Cloud Functions, you're supposed to connect with Unix Sockets by default. With your current code, you will encounter "Not Found" runtime error. You should fix it by changing your host to:
const host = '/cloudsql/gircapp2:us-central1:gircpostgres'

How to Add Firebase Firestore Data into SSR Nuxt Apps Vuex Store

I'm trying to set locations into a Vuex store in my Nuxt app. I've looked into using vuexfire, however, I'm unsure if this would be optimal in a SSR app or generally what is the most simple best practice.
How do you request from firebase firestore and set the state (of the 'locations' in this example)?
Would it be best to use nuxtServerInit in a SSR app?
store/index.js
import Vuex from 'vuex'
import firebase, {auth, db} from '#/services/firebaseinit.js'
const createStore = () => {
return new Vuex.Store({
state: {
user: null,
locations: [],
},
getters: {
// User
activeUser: (state) => {
return state.user
},
// Locations
loadedLocations(state) {
return state.loadedLocations
}
},
mutations: {
// User
setUser (state, payload) {
state.user = payload
},
// Locations
setLocations (state, locations) {
state.locations = locations
}
},
actions: {
// Locations
setLocations(vuexContext, locations) {
vuexContext.commit('setLocations', locations)
},
// Users
autoSignIn ({commit}, payload) {
commit('setUser', payload)
},
signInWithFacebook ({commit}) {
return new Promise((resolve, reject) => {
auth.signInWithPopup(new firebase.auth.FacebookAuthProvider())
resolve()
})
},
signOut ({commit}) {
auth.signOut().then(() => {
commit('setUser', null)
}).catch(error => console.log(error))
},
}
})
}
I haven't used vuexfire but have used firebase with nuxt and it works pretty well. this is what I did.
npm install --save firebase
create a file called firebase.js and put this sort of code in it:
import * as firebase from 'firebase'
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: '<your-api-key>',
authDomain: '<your-domain>',
databaseURL: '<your-url>',
projectId: '<your-id>',
storageBucket: '<your-bucket>'
})
}
export { firebase }
then you register that file as a plugin in nuxt.config.js
plugins: [
'#plugins/firebase.js'
],
You need to import firebase at the top of your index.js (or other file you're using it in) in the store.
import * as firebase from 'firebase'
then you can use firebase in your nuxtServerInit as you want. Eg.
actions: {
nuxtServerInit({dispatch}, context) {
return Promise.all([
dispatch('get_posts', context),
dispatch('any_other_actions', context)
]);
},
get_posts (vuexContext, context) {
return firebase.database().ref(YOUR DB).once('value')
.then(res => {
//...What you want it to do here
})
},
Firebase is pretty powerful and you'll want to read the docs for specifics about the functions you want to perform but yeah, goes good in nuxt.

Resources