how do i authenticate my vuejs app using azure active directory and get the security groups to which the user belong to - vue.js

i saw something similar here: How do you authenticate a VueJS app with Azure AD?
but it did not work for me...
my problem is that after authenticating the user at login - i still needed to get the users security groups and that information was not received using the graph-api described in the above mentioned post
thank you for any help

it was something that took me a long time to figure out so im posting my findings here, hopfully this will help someone:
this was a hard one for me so im posting here - hopfully this will save some time to someone:
my problem was that i need not only to authenticate my vuejs app with azure-ad, but i need also to get the security groups to which the user is belonging to.
to achive this, this is what i done:
i used the vue-adal sample app mentioned above( you can find it in: https://github.com/survirtual/vue-adal ) - under sample folder.
but i still had to make some changes to make it behave the way i need. the problam was that after logging in with my user the sample app used windows.net graph api for retrieving user info with the token from the user authentication, so i had to change in main.js this:
const graphApiBase = `https://graph.windows.net`
const graphApiResource = '00000002-0000-0000-c000-000000000000'
to this:
const graphApiBase = `https://graph.microsoft.com/v1.0`
const graphApiResource = '00000003-0000-0000-c000-000000000000'
in addition, inside the return url component i had to change the axios query to get the security groups to which the user belongs to..so i changed this (in the home.vue file):
async getUserInfo () {
let res = await this.$graphApi.get(`me`, {
params: {
'api-version': 1.6
}
})
to this:
async getUserInfo () {
let res = await this.$graphApi.post(`/me/getMemberGroups`, {
securityEnabledOnly: true
})
console.log(res)
return res.data
}
and then the data that i received back from the api contained the security groups to which the user belongs to...

Related

FirebaseAuth with SvelteKit on +page.ts load

I have a SvelteKit app and am using Firebase and Node to do simple Google SSO auth. I am using an API that requires the IDToken of the currently signed in user to authenticate requests. Ideally I'd like to use the +page.ts load function to load in the data, something like this:
export const load = (async () => {
// Get user, token
const auth = getAuth();
const user = auth.currentUser;
const token = await user?.getIDToken();
if (!token) throw error(401, "Could not authenticate");
// Use token to get data needed to load page
const data = api.requestData(token);
return { data };
}) satisfies PageLoad;
export const ssr = false;
The issue is that user is always null when this function executes. I imagine this is because this is called before the page loads and Firebase hasn't had a way to access the session and get the current user.
My question is, what approach do I take to solve this without simply requesting the data after the page is rendered? Is there a way to authenticate the user server side? Thanks so much.

Vue PWA caching routes in advance

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.

How to implement Auth0 server-side with Nuxtjs?

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).

Nuxt Vuex Store Cookies Issue

Good time of the day!
After a few weeks of development of my project, i've decided to migrate from plain Vue to Nuxt.
Mainly because i need SSR, although i know that Google can execute JS presented on the page and therefore generate appropriate content for their search bot.
Another reason is a general workflow of the project development. I like idea with automatic instantiation of routes, store, etc.
I've faced, however, a pretty strange behavior of the application when it is running in the mode: universal instead of mode: spa. And i don't want to switch to mode: spa since then i lose the SSR i was migrating for in the first place.
I' have an account module in the store - account.js which is responsible for handling any operations related to the account management, such as login/logout, get profile of authenticated user, store the token obtained from the login request as well as the logic for handling the 2FA TOTP procedure.
In my legacy application, i was able to get the token from the cookies by just using the following bit of the code
import Cookies from 'js-cookie';
export const state = {
user: null,
token: Cookies.get('token')
}
And save token after the successful authentication by executing the following mutation:
[types.ACCOUNT_SAVE_TOKEN] (state, { token, remember }) {
state.token = token;
Cookies.set('token', token, {
expires: 365,
httpOnly: true
});
}
But after migration to Nuxt.js, every time im loggin in, the token value in the state is getting populated, but no cookie is set, and after navigating to the other page inside the project (it is pwa, so no reloading, etc) token is reset back to null.
This issue however is gone if application is switched to the mode: spa from mode: universal and everything is working just fine.
I've read many issues on the github as well as done pretty big portion of crawling throught the websites which are trying to solve the same issue, though none of the suggestions are working for me.
I've even installed the cookie-universal-nuxt package from NPM which claims to be working with the SSR, but yet every time I'm trying to access this.$cookies.get('token') in the state, or anywhere else (mutations for example), I'm just getting error about using the method (get/set/remove) on null.
Does anyone know or have an idea on how to overcome this issue, at least if it is possible without going back to the mode: spa?
P.S. Running npm run build|generate yields same files as for the normal vue (without the content, just the structure until the target element is readched) while in mode: spa.
Okay, after around 12 hours trying to wrap my head around this issue, i've decided to go the 'dirty' way and create middleware which is doing, in my opinion, way to much processing on each request.
import CookieParser from 'cookieparser';
export default async function ({ store, req }) {
if (!store.getters['account/check']) {
if (!store.state.account.token) {
if (process.server) {
let requestCookies = CookieParser.parse(req.headers.cookie);
if (requestCookies.hasOwnProperty('token')) {
store.dispatch('account/saveToken', {
token: requestCookies.token,
remember: true
});
}
}
}
if (store.state.account.token) {
if (!store.state.account.user) {
try {
await store.dispatch('account/fetchUser');
} catch (error) { }
}
}
}
return Promise.resolve();
}
Seems like useCookie has been created for this use case

Initial authentication check in ReactJS and Redux

Background: I have an app that is showing a list of movies, but what I want to do is to show the list only for users who are authorized (by checking token stored on the local-storage).
so the flow I want to achieve is:
user enters the app main page
check if has token in local storage
if yes check if it is authorized
if authorized = show list, else don't show
so what I do right now is in my main (wrapper) component right after I create my store:
const store = configureStore();
var token = localStorage.get(authConstants.LOCAL_STORAGE_TOKEN_KEY);
if(token){
store.dispatch(actions.checkInitialAuth(token));
}
checkInitialAuth actions is:
export function checkInitialAuth(token){
return dispatch => {
dispatch(requestLogin());
return fetch(authConstants.API_USER_DETAILS, {headers: { 'Authorization' : `Bearer ${token}`}})
.then(function(response){
if(!response.ok){
throw Error(response.statusText);
}
return response.json();
})
.then(function(user){
localStorage.set(authConstants.LOCAL_STORAGE_TOKEN_KEY, token);
dispatch(receiveLogin(user)); // <==========
dispatch(setTopMovies()); // <==========
})
.catch(function(err){
// TODO: handle errors
console.log(err);
});
}
}
so the question is, is it the right place to invoke the initial auth check right after the creating store and right before the element creation?
and now if I have to invoke more actions only if the user is authorized do I have to invoke them in the then inside the checkInitialAuth action? is it the right place to make all the action dispatch calls?
and last one, when the auth is wrong (I changed manually the token to be wrong on the local storage) the console.log(err) is logging as expected but I have also this annoying 401 error in the console, can I somehow avoid it?
thanks a lot!
is it the right place to invoke the initial auth check right after the creating store and right before the element creation?
Yes. Usually this is where all the initialization happens before store is passed to Provider.
is it the right place to make all the action dispatch calls?
This depends a lot on your application logic. You component can check if a user is authenticated itself to display the correct content for 'topMovies'. But nothing stops you from dispatch more actions here.
but I have also this annoying 401 error in the console, can I somehow avoid it?
It is the network request error. It is the response from the server your fecth is contacting. You can hide the error by change your Chrome Dev console filter if you really want to hide them (but why?).