I am trying to write an FirefoxOS app for my portal which uses Mozilla Persona for authentication. How I should proceed if I want to achieve:
Allow users of my app to signup to my portal using Persona
Allow users of my app to login to my portal within the FirefoxOS app and perform some actions with the API
Depends if users is logged or not - giving access to different actions.
I have found this post with info that its integrated already: http://identity.mozilla.com/post/47114516102/persona-on-firefox-os-phones but I can't find any real examples.
What type of application I need to create? webapp or privileged?
I am trying to implement it using regular tutorial: https://developer.mozilla.org/en/Persona/Quick_Setup
But with this code:
signinLink.onclick = function() { navigator.id.request(); };
I am getting only following error:
[17:25:18.089] Error: Permission denied to access object
One thing is to make sure you're calling watch() to setup callbacks before you call request().
For example, something like this in your page:
<script src="https://login.persona.org/include.js"></script>
<script>
window.addEventListener("DOMContentLoaded", function() {
navigator.id.watch({
// Provide a hint to Persona: who do you think is logged in?
loggedInUser: null,
// Called when persona provides you an identity assertion
// after a successful request(). You *must* post the assertion
// to your server for verification. Never verify assertions
// in client code. See Step 3 in this document:
// https://developer.mozilla.org/en/Persona/Quick_Setup
onlogin: function(assertion) {
// do something with assertion ...
// Note that Persona will also call this function automatically
// if a previously-signed-in user visits your page again.
},
onlogout: function() {
// handle logout ...
},
onready: function() {
// Your signal that Persona's state- and callback-management
// business is complete. Enable signin buttons etc.
}
});
// Set up click handlers for your buttons
document.getElementById("signin").addEventListener(
'click', function() {
navigator.id.request({
// optional callback to request so you can respond to
// a user canceling the sign-in flow
oncancel: function() { /* do something */ }
});
}
});
});
</script>
Here's an example that shows this in action:
https://people.mozilla.org/~jparsons/persona_example.html
However, on FirefoxOS, you should be aware that installed apps (not packaged or certified, but generic installed apps) are given a unique origin of the form app://{uuid}, with a different uuid for each device. This is unfortunately useless for sign-in purposes because there's no way for your server to know whether an app requesting sign-in is friend or foe. The way around this problem is to run your persona code in an invisible iframe hosted on your server. Thus the iframe will have the correct origin and your server will know it's your app. The iframe and the app can communicate via postMessage.
In the case of a packaged app (sometimes called a privileged app), your origin will be the origin declared in your webapp manifest. E.g., app://yourapp.yoursite.org. This gives you better assurance that the app is really yours, but the truly paranoid may still wish to deploy the iframe trick.
Hope this helps!
j
Related
I'm hoping someone can tell me if I'm barking up the wrong tree. I have built a basic web app using Vue CLI and included the PWA support. Everything seems to work fine, I get the install prompt etc.
What I want to do, is cache various pages (routes) that user hasn't visited before, but so that they can when offline.
The reason here is that I'm planning to build an app for an airline and part of that app will act as an in flight magazine, allowing users to read various articles, however the aircrafts do not have wifi so the users need to download the app in the boarding area and my goal is to then pre cache say the top 10 articles so they can read them during the flight.
Is this possible? and is PWA caching the right way to go about it? Has anyone does this sort of thing before?
Thanks in advance
To "convert" your website to an PWA, you just need few steps.
You need to know that the service worker is not running on the main thread and you cant access for example the DOM inside him.
First create an serviceworker.
For example, go to your root directory of your project and add a javascript file called serviceworker.js this will be your service worker.
Register the service worker.
To register the service worker, you will need to check if its even possible in this browser, and then register him:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope');
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
In vue.js you can put this inside mounted() or created() hook.
If you would run this code it will say that the service worker is successfully registered even if we havent wrote any code inside serviceworker.js
The fetch handler
Inside of serviceworker.js its good to create a variable for example CACHE_NAME. This will be the name of your cache where the cached content will be saved at.
var CACHE_NAME = "mycache_v1";
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
return cache.match(event.request).then(function (response) {
return response || fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
Everytime you make a network request your request runs through the service worker fetch handler here first. You need to response with event.respondWith()
Next step is you first open your cache called mycache_v1 and take a look inside if there is a match with your request.
Remember: cache.match() wont get rejected if there is no match, it just returns undefined because of that there is a || operator at the return statement.
If there is a match available return the match out of the cache, if not then fetch() the event request.
In the fetch() you save the response inside the cache AND return the response to the user.
This is called cache-first approach because you first take a look inside the cache and in case there is no match you make a fallback to the network.
Actually you could go a step further by adding a catch() at your fetch like this:
return response || fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
})
.catch(err => {
return fetch("/offline.html")
});
In case there is nothing inside the cache AND you also have no network error you could response with a offline page.
You ask yourself maybe: "Ok, no cache available and no internet, how is the user supposed to see the offline page, it requires internet connection too to see it right?"
In case of that you can pre-cache some pages.
First you create a array with routes that you want to cache:
var PRE_CACHE = ["/offline.html"];
In our case its just the offline.html page. You are able to add css and js files aswell.
Now you need the install handler:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(PRE_CACHE);
})
);
});
The install is just called 1x whenever a service worker gets registered.
This just means: Open your cache, add the routes inside the cache. Now if you register you SW your offline.html is pre-cached.
I suggest to read the "Web fundamentals" from the google guys: https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook
There are other strategies like: network-first
To be honest i dont know exactly how the routing works with SPAs because SPA is just 1 index.html file that is shipped to the client and the routing is handled by javascript you will need to check it out witch is the best strategie for your app.
I have a Nuxt app with authentication already running in universal mode.
I'm trying to convert the authentication service to Auth0. I'm following the Vue quickstart, but I discovered that auth0-js is a client side library since it uses a lot of 'window'-stuff that is not available on the server-side of Nuxt.
However, I got it kind of working by making it a client-side plugin and wrap all functions (that is calling the authservice in the lifecycle hooks) in a process.client check. It works "kind of" because when going to the protected page whilst not logged in, it flashes the page before being redirected to login page (since its rendered on the server-side as well, but the check only happens once it's delivered on the client side I presume).
My question now is: What can I do in order to add the check to server-side as well? (or at least make sure that the protected pages isn't flashed before being redirected).
What I've tried so far:
Saving the payload and the logged-in state in the store and check in some custom middleware, but that didn't do the trick.
Also, it seems to me that #nuxt/auth is outdated or something and the nuxt auth0 example as well. It uses auth0-lock while I'm using the new auth0 universal.
Anyone have suggestions on how to solve this issue? Thanks in advance!
not sure if this will be any help and have only answered a few questions (other account long time ago).
Update.. I read my answer then the question title (I think my answer does cover some of your context), but in regards to the title you could also look at using auth as a plugin. You can then handle stuff there before the page is hit.
I am not sure how your code is implemented, but this may help (hopefully).
If you are not using Vuex, I strong recommend it. Nuxt Vuex Store Guide
// index/store.js
// At least have the store initialized, but its most likely going to be used..
// page.vue
<template>
...
<div v-else-if="!$auth.loggedIn">
{{ test }}
</div>
...
...
data() {
if (!this.$auth.loggedIn) {
const test = 'Only this will load, no flash'
return { test }
}
}
$auth.loggedIn is built in, I read it ..somewhere.. in the docs
This will solve the no flash issue, you can also take advantage of a loader screen and asyncData to check the state before rendering the view to avoid a flash and populate data if it hangs.
You could also try using Vuex Actions, I am currently playing with these 2 in the process of where I am now. Learning about nuxtServerInit()
// store/index.js
import axios from 'axios'
export const actions = {
nuxtServerInit ({commit}, {request}) {
// This is good if you have the user in your request or other server side stuff
if (request.user) commit('SET_USER', request.user)
},
async GET_USER({ commit }, username) {
const user = await axios.get(`/user/${username}`)
if (user) commit('SET_USER', user)
}
}
export const mutations = {
SET_USER(state, user) {
// simple set for now
state.auth.user = user || null
}
}
The second one is combined using the fetch() method on the page itself.
// page.vue
async fetch({ $auth, store }) {
await store.dispatch('GET_USER', $auth.$state.user)
}
Now you can call $auth.user in your code as needed.
$auth.user is another built in I read ..somewhere..
You can also call $auth.user with the $auth.loggedIn to check if user exists on top of being logged in $auth.user && $auth.loggedIn.
It may be this.$auth.<value> depending on where you are trying to reference it.
I learned the asyncData() gets call first and logs in my server, then data() logs values in the server console as well (false, null), but in my Brave console they're undefined, i'd like an answer to that lol
I have been struggling with trying to get Auth0 to work how I wanted with JWTs, but as I kept crawling I found useful bits along the way (even in old demos such as the one you mentioned, just nothing with the lock stuff...). Also in terms of express and my API in general... Anyways, hope this helped (someone).
How can I add check whether user is logged or not and in accordance with that, allow navigation to desired page or not? It wouldn't be good practice to add :
ionViewCanEnter() {
return this.auth.isAuthenticated();
}
check at the top of every component...
I recommend using an authentication token for your user login. This will allow you to locally store as a variable or local storage and you can implement in your service or provider to be used throughout the app. If you're uncertain with how they work there are plenty of resources online, but ultimately it comes down to your back-end server. Here's an example:Auth Token Example
Also, I would recommend you use *ngIf statement blocks in your html pages where the buttons navigate to the pages themselves and throw an alert if the user tries clicking on the button to navigate.
I have some sample code that can help guide you with this as well.
LoginPage.ts
// API POST authentication
this.API.validateUser(form.value).then((result) =>{
form.reset();//clears values of the form after data is saved to array
this.res = JSON.parse(result.toString());//converts result to array
//console.log(this.res);
if(this.res.token!=""){//sets authtoken to local storage
this.storage.set('authToken',this.res.token)
}
//console.log(localStorage);
if(this.res.status == true){
setTimeout(() => {
LoginPage.initialLogin = true;
this.navCtrl.push(MenuPage);
loading.dismiss();
}, 1000);
}
MenuPage.ts
// MenuPage.ts
/* calls local storage once user hits menupage*/
if(LoginPage.initialLogin==true){
//console.log('Initial Login is:',LoginPage.initialLogin);
this.storage.get('authToken').then((data)=>{//grabs local storage auth token
if(data!=null){
//console.log('GET request happened');
this.loggedIn = true;//User is logged in
this.reap.grabAPIData(data);//calls service to grab API data on initial login
}
});
}
else{
this.reap.getLocalStorage();
//console.log('Initial Login is:',LoginPage.initialLogin);
}
MenuPage.html
This is where you can use your value to determine what the user can see or not see. The button can be hidden or you can throw an alert in the .ts file that lets user know they aren't logged in.
<ion-item *ngIf="loggedIn" no-lines>
<button class="menuButton" ion-button large block (tap)="toNexPage()" >
Next page</button>
</ion-item>
I am starting with Polymer and Firebase and have implemented the Google OAuth authentication.
I have notice the page loads before authentication and if you click back you can get to the page without authorization, albeit that you are not able to use the firebase api and therefore the page is not usable.
My issue is that I do not want my javascript loaded until authenticated.
How could this be done.
Many thanks
It depends if your using firebase or their polymer wrapper, polymerfire.
Create a document for all the imports that you want to be conditionally loaded
// user-scripts-lazy.html
<link rel="import" href="user-script-one.html">
<script src="script.js"></script>
// etc
Using Polymerfire
In the element that hosts <firebase-auth> create a observer and you'll expose some variables from firebase-auth.
<firebase-auth
user="{{user}}"
status-known="{{statusKnown}}"></firebase-auth>
In the observer, watch the user element and the status known
statusKnown: When true, login status can be determined by checking user property
user: The currently-authenticated user with user-related metadata. See the firebase.User documentation for the spec.
observers:[
'_userStateKnown(user, statusKnown)'
]
_userStateKnown: function(user, status) {
if(status && user) {
// The status is known and the user has logged in
// so load the files here - using the lazy load method
var resolvedPageUrl = this.resolveUrl('user-scripts-lazy.html.html');
this.importHref(resolvedPageUrl, null, this.onError, true);
}
}
To get the state without using polymerfire you can use onAuthStateChange
properties: {
user: {
type: Object,
value: null // important to initialise to null
}
}
..
ready: function() {
firebase.auth().onAuthStateChagned(function(user) {
if(user)
this.set('user', user); // when a user is logged in set their firebase user variable to ser
else
this.set('user', false); // when no user is logged in set user to false
}.bind(this)); // bind the Polymer scope to the onAuthStateChanged function
}
// set an observer in the element
observers: [
'_userChanged(user)'
],
_userChanged: function(user) {
if(user === null) {
// authStatus is false, the authStateChagned function hasn't returned yet. Do nothing
return;
}
if(user) {
// user has been signed in
// lazy load the same as before
} else {
// no user is signed in
}
}
I haven't tested the code while writing it here, but i've implemented the same thing various times.
There are a couple of options.
Put content you don't want loaded behind a dom-if template with "[[user]]" as its driver. This could include your firebase element, so the database isn't even considered until after log on.
Put a modal dialog box up if the user is not logged on. I do this with a custom session element . Whilst the overlay is showing then the rest of the page is unresponsive to anything.
If it is simply an aesthetic issue of removing the non-logged-in page from view, could you either hide the page (or display some kind of overlay) while the user isn't authenticated?
I currently have this in an current project for some elements: hidden$="{{!user}}"
I have identified the solution for my purpose ...
Add storage role based authorization (see is there a way to authenticate user role in firebase storage rules?)
This does have a limitation currently of hard coded uid's
In the page, request storage resource and if successful include it in the dom (i.e. add script element with src pointing to storage url)
Call javascript as normal
what i'm trying to do is lock down certain pages in my durandal(knockoutjs/breezejs) SPA app based on a user's authenticated role (ie, if you're an admin, etc, you should see pages that others shouldn't).
ideally, server code could be used to either output the link or not based on role, but since durandal and SPA apps don't really work that way with server code, i'm at a loss.
i realize this question has been asked in other forms here (i.e. how to use .cshtml (server) pages with Durandal), and this could be an option if perhaps i could get it to work. i have yet to find a very complete example that works for me.
any ideas appreciated!
You can keep your routing information on the server and supply it to the application on initialization.
For example. In the activate method of your shell viewmodel
shell.js
define(['durandal/system', 'plugins/router', 'durandal/app', 'services/datacontext'],
function (system, router, app, datacontext) {
var routeInfo = ko.observable();
var shell = {
activate: activate,
router: router
};
return shell;
//#region Internal Methods
function activate() {
app.title = "Sample App";
return boot();
}
function boot() {
return datacontext.getRouteInformation(routeInfo).then(function() {
return router.map(routeInfo()).buildNavigationModel().mapUnknownRoutes('error', 'Error').activate();
});
}
//#endregion
});
my datacontext.getRouteInformation() gets a json array of route information based on the current users security context and populates the routeInfo observable. that observable is then passed to the map function to create the users valid routes etc.
I know this doesn't fully "lock down" the html files etc, but all of my controllers and actions have authorization attributes on them, so the data is protected.