I have anonymous auth working.
Flutter: signed in! FirebaseUser({displayName: null, providerId: Firebase, uid: 6vj0tYIQsUSjsdiJfkjid37NhKk2, providerData: [], isEmailVerified: false, email: null, photoUrl: null, isAnonymous: true})
And my rules are as follows
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
And I keep getting this error
But if I change my rules to public
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if true;
}
}
}
It works!
Any idea what's going on?
This is my code. I cannot find anywhere to feed it my auth information, and I'm not sure if I even have to.
final DatabaseReference dbRef = FirebaseDatabase().reference();
final StorageReference storageRef = FirebaseStorage().ref();
final FirebaseAuth auth = FirebaseAuth.instance;
Future<void> connect() async {
this.app = await FirebaseApp.configure(
name: 'when-coin-test',
options: const FirebaseOptions(
googleAppID: '1:3739845793845:ios:9287349823487',
apiKey: 'AoijojsoafhsdiohIOSHFOSHfoiShdfoijdf',
databaseURL: 'https://when-coin-test.firebaseio.com',
storageBucket: 'gs://when-coin-test.appspot.com'
)
);
print("connected to firebase!");
this.user = await this.auth.signInAnonymously();
print("signed in! $user");
await _getAllSocialImageUrls();
print("got socialUrls! $socialUrls");
}
I think that the credentials you passed into configure are just not working.
The configuration of Firebase for Flutter is not documented everywhere. Following step 1. for Android and step 2. for iOS right here, you are already set up with your credentials.
FirebaseAuth will work with that and automatically integrate with the other Firebase plugins, like Firebase Storage.
Because of this, you can actually omit all of this:
this.app = await FirebaseApp.configure(
...
);
You can still use FirebaseApp if you would like to work with multiple projects, but for your use case, you do not need to access the class at all.
firebase_core's purpose as a package is describe on the page as follows:
Firebase Core for Flutter
A Flutter plugin to use the Firebase Core API, which enables connecting to multiple Firebase apps.
I was curious and so I went to initiate the FirebaseApp without the .configure() method (as creativecreatorormaybenot mentioned).
Doing it this way, everything works fine.
app = FirebaseApp(name: 'when-coin-test');
user = await this.auth.signInAnonymously();
This example is out of date: https://github.com/flutter/plugins/blob/master/packages/firebase_core/example/lib/main.dart
Use FirebaseAuth.fromApp(app) instead of FirebaseAuth.instance. Or you can use my simple FirebaseWrapper.
import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
await FirebaseWrapper.init();
runApp(
MyApp(),
);
}
class FirebaseWrapper {
static FirebaseAuth _auth;
static Firestore _firestore;
static FirebaseStorage _storage;
static Future<void> init() async {
WidgetsFlutterBinding.ensureInitialized();
final FirebaseApp app = await FirebaseApp.configure(
name: 'Overload',
options: FirebaseOptions(
googleAppID: Platform.isIOS ? '1:0000000000:ios:000000000000' : '1:fbfbfbfbfbfbfbbf:android:fbfbfbfbfbfbfbfbf',
gcmSenderID: '14325256252',
apiKey: 'JHasjkhvKJKhfgKfdlLDFLkDLkDJhD',
projectID: 'some-project-id',
),
);
_auth = FirebaseAuth.fromApp(app);
_firestore = Firestore(app: app);
_storage = FirebaseStorage(
app: app, storageBucket: 'gs://overload-57752.appspot.com');
}
static FirebaseAuth auth() {
return _auth;
}
static Firestore firestore() {
return _firestore;
}
static FirebaseStorage storage() {
return _storage;
}
}
Related
I've managed to get JWT authentication in my nestJS application.
Now I want to implement the role guard and have therefore to check the role of the authenticated user.
Therefore, I thought of requesting the respective user role from the database. But this call is async and this is not doable within the guard.
My question is:
How can I get the user role information within the Guard?
I could put the information in the JWT token, but this seems not right to me, or am I wrong?
Here, Implementing Passport JWT you can put your findUser in the validate function that is async. And then create a decorator to return the user Auth JWT in decorator in NESTJS
So you need to do some things like this
//jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable } from '#nestjs/common';
import { jwtConstants } from './constants';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
async validate(payload: any) {
// Your JWT payload
// Insert here the findOne from you're BDD
return { userId: payload.sub, username: payload.username };
}
}
And then
//user.decorator.ts
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const User = createParamDecorator((data: any, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
});
And in your controller juste use
//user.controller.ts
import { User } from './user.decorator';
#Get()
async getUser(#User() user) {
//console.log(user);
}
I am new in NestJS and trying to do auth system. I was able to do. So here is what I am doing to get access to auth.
In my controller I have
#Get('/user')
async getUser(#AuthUser() token: string) : Promise<Object> {
return this.authService.getUser(token)
return token
}
Here I am passing a AuthUser decorator I want to avoid passing in controllers.
In the authService.getUser method I have something like this
async getUser(token: string): Promise<Object> {
try {
const user = await this.jwtService.verifyAsync(token)
return user
} catch (error) {
return false
}
}
and my decorator looks like this
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const AuthUser = createParamDecorator(
(data = 'u_ses', ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return data ? request.cookies?.[data] : request.cookies;
},
);
I don't like code. If I need to know the user id from a service class or anywhere I would need to pass the token and to get token I need use #AuthUser() token: string)
So I want to do something like this
this.authService.getUser(), here I don't want to pass token or anything and should be able to access this getUser method from anywhere. Since it's a service class, I can inject and use it but I won't have the token.
I tried injecting the decorator inside the service class, but this doesn't work.
One best solution I would prefer is to use the JWT things inside the decorator, so I don't need the service class' method :)
I am looking for a nicer solutions from you :)
Thank you.
Nestjs has NestMiddleware. Here, you can authorize before access to controller like this:
import { Injectable, NestMiddleware, UnauthorizedException } from '#nestjs/common';
import { Request, Response, NextFunction } from 'express';
#Injectable()
export class AuthenticationMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const headerAuthentication = req.headers.authorization;
if(!headerAuthentication) throw new UnauthorizedException('Authorization failed!');
const token = req.headers.authorization.split(' ')[1];
if(token) {
next();
}else {
throw new UnauthorizedException('Authorization failed!');
}
}
}
and in AppModule implement it
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthenticationMiddleware).forRoutes('/');
}
}
The route I want to protect: /account
If the user is NOT authenticated, then redirect to /signIn
Having an SSR NextJS project, and working with Firebase authentication, how can I achieve a production battle-tested proper protected routes?
The example provided on NextJS docs is not working right now:
with-firebase-auth
So I submitted an issue:
with-firebase-auth-example-not-working
Add to that that I'm new to NextJs and also, unfortunately, I've never used JWT :( or any sort of backend protected routes cookies/JWT/sessions implementation....Until now that I want/need it.
What sort of workaround I've tried, well, something like this:
import Account from "./Account.js";
import Loading from "./Loading.js";
import { useRequireAuth } from "./use-require-auth.js";
function Account(props) {
const auth = useRequireAuth();
// If auth is null (still fetching data)
// or false (logged out, above hook will redirect)
// then show loading indicator.
if (!auth) {
return <Loading />;
}
return (
<Account auth={auth} />
);
}
// Hook (use-require-auth.js)
import { useEffect } from "react";
import { useAuth } from "./use-auth.js";
import { useRouter } from "./use-router.js";
function useRequireAuth(redirectUrl = '/sigIn'){
const auth = useAuth();
const router = useRouter();
// If auth.user is false that means we're not
// logged in and should redirect.
useEffect(() => {
if (auth.user === false){
router.push(redirectUrl);
}
}, [auth, router]);
return auth;
}
But this is all happening on the client-side....the server is not checking anything.
I'm gonna a post a very basic answer to this. I dunno how you're going to check if a user is authenticated on firebase. My own code uses AWS Cognito for this purpose.
We' are going to put that piece of code at the end of the page. By doing so, if the user is not authenticated we will redirect the user to the sign in page.
export async function isAuthenticated(context) {
// your code to check firebase authentication
// return true if not authenticated, else return false
// Maybe this way
var user = firebase.auth().currentUser;
if (user)
return false;
else
return true;
}
export const getServerSideProps: GetServerSideProps = async (ctx) => {
let shouldRedirect = await isAuthenticated(ctx);
if (shouldRedirect) {
return {
redirect: {
destination: '/sign-in',
permanent: false
}
}
}
return {
props: {}
}
}
export default Account;
That's it. Now the route is protected through SSR.
I was following this article here (which is not complete unfortunately) in attempt to learn how to friend Ionic 3 based PWA and Firebase Cloud Messaging: Push Notifications with FCM
What I did:
as advised in the article added FCM libraries into service-worker.js:
'use strict';
importScripts('./build/sw-toolbox.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging');
firebase.initializeApp({
// get this from Firebase console, Cloud messaging section
'messagingSenderId': '47286327412'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler((payload) => {
console.log('Received background message ', payload);
// here you can override some options describing what's in the message;
// however, the actual content will come from the service sending messages
const notificationOptions = {
icon: '/assets/img/appicon.png'
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
self.toolbox.options.cache = {
name: 'ionic-cache'
};
// pre-cache our key assets
self.toolbox.precache(
[
'./build/main.js',
'./build/vendor.js',
'./build/main.css',
'./build/polyfills.js',
'index.html',
'manifest.json'
]
);
// dynamically cache any other local assets
self.toolbox.router.any('/*', self.toolbox.cacheFirst);
// for any other requests go to the network, cache,
// and then only use that cached resource if your user goes offline
self.toolbox.router.default = self.toolbox.networkFirst;
Then created Firebase Messaging based provider here:
import { Injectable } from "#angular/core";
import * as firebase from 'firebase';
import { Storage } from '#ionic/storage';
#Injectable()
export class FirebaseMessagingProvider {
private messaging: firebase.messaging.Messaging;
private unsubscribeOnTokenRefresh = () => {};
constructor(
private storage: Storage
) {
this.messaging = firebase.messaging();
}
public enableNotifications() {
console.log('Requesting permission...');
return this.messaging.requestPermission().then(() => {
console.log('Permission granted');
// token might change - we need to listen for changes to it and update it
this.setupOnTokenRefresh();
return this.updateToken();
});
}
public disableNotifications() {
this.unsubscribeOnTokenRefresh();
this.unsubscribeOnTokenRefresh = () => {};
return this.storage.set('fcmToken','').then();
}
private updateToken() {
return this.messaging.getToken().then((currentToken) => {
if (currentToken) {
// we've got the token from Firebase, now let's store it in the database
return this.storage.set('fcmToken', currentToken);
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
});
}
private setupOnTokenRefresh(): void {
this.unsubscribeOnTokenRefresh = this.messaging.onTokenRefresh(() => {
console.log("Token refreshed");
this.storage.set('fcmToken','').then(() => { this.updateToken(); });
});
}
}
And now during app initialization I call enableNotifications() and get error that says that default service worker is not found (404):
A bad HTTP response code (404) was received when fetching the script.
:8100/firebase-messaging-sw.js Failed to load resource: net::ERR_INVALID_RESPONSE
If I move service-worker.js firebase related stuff into default service worker in WWW folder - I get general error from Firebase (Error, failed to register service worker).
QUESTIONS:
- is there a fresh guide on Ionic 3's PWA & FCM?
- at high level what is the difference in registering service workers in Ionic 3 vs Angular? I did watch the tutorial about Angular but can't figure how to do the same in Ionic 3.
UPDATE: the below is valid as of today (02/12/2018) and most likely will be less relevant once AngularFire2 supports messaging module. So take the below with that assumption...
OK I researched and finally made it work on my Ionic 3 PWA, so I am posting solution here:
Prerequisites:
I created ionic blank app (just a home page)
installed angularfire2 and firebase ("angularfire2": "5.0.0-rc.4","firebase": "4.9.1") using npm install, I used specifically 5.0.0-rc.4" cause I had stability issues with latest one;(
created config (filename environment.ts in src folder):
export const firebaseConfig = {
apiKey: "Your Stuff Here from FB",
authDomain: "YOURAPPNAME.firebaseapp.com",
databaseURL: "https://YOURAPPNAME.firebaseio.com",
projectId: "YOURAPPNAME",
storageBucket: "YOURAPPNAME.appspot.com",
messagingSenderId: "FROMFIREBASECONEOLE"
};
I modified app.module.ts to add firebase and angularfire2 this way:
...
import { AngularFireModule } from 'angularfire2';
import 'firebase/messaging'; // only import firebase messaging or as needed;
import { firebaseConfig } from '../environment';
import { FirebaseMessagingProvider } from '../providers/firebase-messaging';
...
#NgModule({
declarations: [
MyApp,
HomePage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
AngularFireModule.initializeApp(firebaseConfig),
IonicStorageModule.forRoot()
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
FirebaseMessagingProvider,
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
Here we also import our provider whose code is below:
in providers folder I created firebase-messaging.ts like this:
import { Injectable } from "#angular/core";
import { FirebaseApp } from 'angularfire2';
// I am importing simple ionic storage (local one), in prod this should be remote storage of some sort.
import { Storage } from '#ionic/storage';
#Injectable()
export class FirebaseMessagingProvider {
private messaging;
private unsubscribeOnTokenRefresh = () => {};
constructor(
private storage: Storage,
private app: FirebaseApp
) {
this.messaging = app.messaging();
navigator.serviceWorker.register('service-worker.js').then((registration) => {
this.messaging.useServiceWorker(registration);
//this.disableNotifications()
this.enableNotifications();
});
}
public enableNotifications() {
console.log('Requesting permission...');
return this.messaging.requestPermission().then(() => {
console.log('Permission granted');
// token might change - we need to listen for changes to it and update it
this.setupOnTokenRefresh();
return this.updateToken();
});
}
public disableNotifications() {
this.unsubscribeOnTokenRefresh();
this.unsubscribeOnTokenRefresh = () => {};
return this.storage.set('fcmToken','').then();
}
private updateToken() {
return this.messaging.getToken().then((currentToken) => {
if (currentToken) {
// we've got the token from Firebase, now let's store it in the database
console.log(currentToken)
return this.storage.set('fcmToken', currentToken);
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
});
}
private setupOnTokenRefresh(): void {
this.unsubscribeOnTokenRefresh = this.messaging.onTokenRefresh(() => {
console.log("Token refreshed");
this.storage.set('fcmToken','').then(() => { this.updateToken(); });
});
}
}
Please note I init the firebase app and then in constructor we register ionic's default service worker (service-worker.js) that contains the following right after whatever is there by default:
service-worker.js:
// firebase messaging part:
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging.js');
firebase.initializeApp({
// get this from Firebase console, Cloud messaging section
'messagingSenderId': 'YOURIDFROMYOURFIREBASECONSOLE'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('Received background message ', payload);
// here you can override some options describing what's in the message;
// however, the actual content will come from the Webtask
const notificationOptions = {
icon: '/assets/images/logo-128.png'
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
At this point you also need to make sure you enabled your app as PWA, there is a good guide from Josh Morony and today there was a video stream on youtube that covers it. In TLDR you need to uncomment this in your index.html:
index.html in src uncomment:
<!-- un-comment this code to enable service worker -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.error('Error', err));
}
</script>
OK almost the last thing - your manifest.json (in src) should have exact line:
"gcm_sender_id": "103953800507"
This concludes initial stuff on the client. Please note I didn't implement yet anything to handle notifications while user is in app itself, think for now it just handles when a message is sent from a server while your tab is not in focus (that is what I tested).
Now you want to go to your firebase console and obtain server key (click setting gear icon, then see cloud messaging section there). Copy server key. Also run the client (ionic serve and capture your local token (i just console.logged it). Now try sending yourself the message using a POST method. ( I did it with Postman)
// method: "POST",
//url: "https://fcm.googleapis.com/fcm/send",
// get the key from Firebase console
headers: { Authorization: `key=${fcmServerKey}` },
json: {
"notification": {
"title": "Message title",
"body": "Message body",
"click_action": "URL to your app?"
},
// userData is where your client stored the FCM token for the given user
// it should be read from the database
"to": userData.fcmRegistrationKey
}
So by doing all this I was able to reliable send myself a message WHILE the app was in background. I am yet to handle foreground but this SO question is about how to init default service worker and marry it with FCM.
I hope this will help some learners in future.
I have successfully implemented the process and got success response on API calls. But no notification popup coming on my browser. Any idea?
api: https://fcm.googleapis.com/fcm/send
response got:
{"multicast_id":6904414188195222649,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1545375125056264%e609af1cf9fd7ecd"}]}
cheth the attached url of my console:
I am trying to use the Auth0 for social login but I keep getting an exception of an undefined reference.
This is the authentication service
import { Injectable } from '#angular/core';
import { tokenNotExpired } from 'angular2-jwt';
// Avoid name not found warnings
declare var Auth0Lock: any;
#Injectable()
export class AuthService {
// Configure Auth0
lock = new Auth0Lock('I have set the ID correctly here', 'and the domain as well', {});
constructor() {
// Add callback for lock `authenticated` event
this.lock.on("authenticated", (authResult) => {
localStorage.setItem('id_token', authResult.idToken);
});
}
public login() {
// Call the show method to display the widget.
this.lock.show();
};
public authenticated() {
// Check if there's an unexpired JWT
// This searches for an item in localStorage with key == 'id_token'
return tokenNotExpired();
};
public logout() {
// Remove token from localStorage
localStorage.removeItem('id_token');
};
}
I injected the services and configured providers. Everything is wired correctly, but it just won't find Auth0Lock even though defined.
Each time it reaches lock = new Auth0Lock('ID', 'DOMAIN', {}); it bombs out.
I replaced declare var Auth0Lock: any; with const Auth0Lock = require('auth0-lock').default; and that fixed the problem.
The accepted answer is good. I did get a Cannot find name 'require' error.
Rather than using 'declare const require', I imported like so:
import Auth0Lock from 'auth0-lock';
I needed to add to index.html:
<script src="https://cdn.auth0.com/js/lock/10.8/lock.min.js"></script>
via https://github.com/auth0/lock/issues/588