Code for passing user information from azureAD to app.js - javascript

I am trying to introduce the Single-Sign-On (SSO) feature to my React app and I want to use the user information from my company for the SSO verification. For that, I registered my application on the Azure website to acquire the clientID. I have found an article that shows how to make use of React AAD MSAL package to enable user login through a popup method: https://www.npmjs.com/package/react-aad-msal .
I create an authProvider.js file with the following code:
// authProvider.js
import { MsalAuthProvider, LoginType } from 'react-aad-msal';
// Msal Configurations
const config = {
auth: {
authority: 'https://login.microsoftonline.com/common',
clientId: 'XXXXXXXXXXXXXXXXXXXXXXX',
redirectUri: 'localhost:3000'
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
// Authentication Parameters
const authenticationParameters = {
scopes: [
'User.Read'
]
}
// Options
const options = {
loginType: LoginType.Popup,
tokenRefreshUri: window.location.origin + '/auth.html'
}
export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
and my index.js file looks like this:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { AzureAD } from 'react-aad-msal';
import App from './App';
import { authProvider } from './authProvider';
ReactDOM.render(
<BrowserRouter>
<AzureAD provider={authProvider} forceLogin={true}>
<App />
</AzureAD>
<BrowserRouter>,
document.getElementById('root'),
);
This code worked and allowed me to authenticate users on the sign in and then redirected them to the redirect URL. I now would like to pass user information such as name, surname, email address and profile picture to the App component.
I was not able to find resources online that would help me do it and the documentation on the npm website does not have examples of that being done. Could anyone provide working code examples of how to do what I want? (All my files are in js and I can not use any code examples provided by Microsoft as they use tsx files and I don't want to change all my files to TypeScript).
Perhaps there are some children or property functions in MsalAuthProvider that I can call but I could not find documentation on that function either. I am also not sure of where to call these functions in index.js so code examples would be very helpful. Thanks

You could get user information with myMSALObj.getAccount() using MSAL.js.
const myMSALObj = new Msal.UserAgentApplication(msalConfig);
function signIn() {
myMSALObj.loginPopup(loginRequest)
.then(loginResponse => {
console.log('id_token acquired at: ' + new Date().toString());
console.log(loginResponse);
if (myMSALObj.getAccount()) {
showWelcomeMessage(myMSALObj.getAccount());
}
}).catch(error => {
console.log(error);
});
}
For more details about the code sample, see here.
Also you could get access token in your code with react-aad-msal. Some information of the user such as username and email will be shown after decoding the token.
import jwtDecode from 'jwt-decode';
const claims = jwtDecode('base64 encoded token received from Azure AD');

Related

Integrate Countly SDK Web with Typescript

Has anyone here has experience integrating Countly SDK Web with ReactJS using Typescript?
The example given here assume people use Javascript to use the SDK. I want to do something like.
import { Countly } from 'countly-sdk-web';
and use it to hit some API that has been created in Countly when webpage load. Any help would be greatly appreciated.
Note: The files is in .tsx extension
you can reach an example on how to integrate Countly Web SDK in a ReactJS project from here.
Again there, a basic example to import Countly would be like this:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App-WithEffect';
import * as serviceWorker from './serviceWorker';
import Countly from 'countly-sdk-web';
//Exposing Countly to the DOM as a global variable
//Usecase - Heatmaps
window.Countly = Countly;
Countly.init({
app_key: 'YOUR_APP_KEY',
url: 'YOUR_SERVER_URL',
session_update: 10,
use_session_cookie: true,
debug: false,
require_consent: true,
namespace: "react-demo",
inactivity_time: 1,
offline_mode: false,
// device_id: "cly-device-demo-id" //Set only if you want dont want to use countly generated device_id
});
//Since Countly is loaded and available, you can use synchronus or asynchronus calls, does not matter
Countly.q.push(['group_features', {
activity: ["sessions", "events", "views", "location"],
interaction: ["scrolls", "clicks", "crashes"],
whereabouts: ["users"]
}]);
if (typeof(localStorage) !== "undefined") {
var consents = localStorage.getItem("consents");
if(consents){
Countly.q.push(['add_consent', JSON.parse(consents)]);
}
else{
var consent = window.confirm("We are going to track you. Do you give your consent ?");
consents = ["activity", "interaction", "whereabouts"];
if(consent) {
Countly.q.push(['add_consent', consents]);
localStorage.setItem("consents", JSON.stringify(consents));
}
else {
Countly.q.push(['remove_consent', consents]);
localStorage.removeItem("consents");
}
}
}
Countly.q.push(['enableRatingWidgets', {'widgets': ['widget-id-1','widget-id-2']}]);
Countly.q.push(['track_sessions']);
Countly.q.push(['track_scrolls']);
Countly.q.push(['track_clicks']);
Countly.q.push(['track_links']);
Countly.q.push(["track_errors"]);
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
You can reach this code from here

How to properly store access token in memory react

I'm searching for a clean way to store my access token in React.
First thing: I don't want to use local storage. I don't need to make my access token persistent since I can always refresh it.
I also excluded a cookie since I want to prevent CSRF attacks. By storing the access token only in memory, in fact, the page needs to be loaded to get the token and authenticate requests (refresh token can be used only to refresh)
I thought of using redux/context, however, the function calling the API is not a child of a component so I can't access the token from that. Furthermore, I don't want to pass the token as a parameter, since I want to keep decoupled the HTTP logic. Maybe there is a clean way to use it?
After a bit of research, I found that using a global variable is a working "cheat" to obtain what I want. However, I was guessing if there was a clearer way to get the same result.
//token.js
const access_token= "";
export const setAccessToken(token){
access_token=token;
}
export const getAccessToken(){
return access_token;
}
//NOTICE:
// -ON LOGIN/REFRESH: I set the access token
// -ON API CALLS: I get the access token and I add it to the header
api.js
const baseURL= "http://my_base_url";
const generateApiInterface = ()=>{
let headers : any= {
};
token=getAccessToken(); //HERE I NEED TO RETRIEVE MY ACCESS TOKEN
if(token){
headers={
'Authorization': 'Token '+ token,
...headers //append other basic proprieties
}
}
return axios.create({
baseURL: baseURL,
headers: headers
});
}
const api = generateApiInterface();
The way you're doing it is preferable to keep anything in memory. If this is server side, then you'd want to make sure you delete the token once you're done, but if not then the current approach is desirable. Note, you're using a const, you'd want to change that to a let. Another idea would be to use session storage, but then that brings the idea of XSS.
However, React provide a way to have "global" state - this would be to use a provider and context. Here's an example:
// provider.tsx
import React, { useContext, createContext, FC, useState } from 'react'
type AccessTokenContext = [string, React.Dispatch<React.SetStateAction<string>>]
const AccessTokenProvider: FC = (props) => {
const [accessToken, setAccessToken] = useState<string>(null)
return <AccessToken.Provider value={[accessToken, setAccessToken]} {...props} />
}
const AccessToken = createContext<AccessTokenContext>(null)
const useAccessToken = (): AccessTokenContext => useContext<AccessTokenContext>(AccessToken)
export { AccessTokenProvider, useAccessToken }
You'd have to wrap your app container in AccessTokenProvider:
// index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { AccessTokenProvider } from './providers/AccessTokenProvider'
ReactDOM.render(
<AccessTokenProvider>
<App />
</AccessTokenProvider>,
document.getElementById('app')
)
Then you can then use the hook useAccessToken in App and any children of App. Of course, this provider doesn't have to be root level, but it's easiest to include it here.
// app.tsx
import React, { FC } from 'react'
const App: FC = props => {
const [accessToken, setAccessToken] = useAccessToken()
return <div>{/* content */}</div>
}
export default App

Unable to expose a public page referenced in an email to let users reset their password in a Vue JS, Node JS and Mongo db website structure

I'm working on a Vue JS, Node and Mongodb website with user management features. I implemented a "Reset Password" functionality: a user can access his profile page, press the reset password button and this will trigger a node functionaly, which is gonna send him an email containing a URL link pointing to a Vue JS component exposed to the public called "ResetPassword".
The URL has this format: /ResetPassword/<token_assiged_to_user>
(for ex. /ResetPassword/5fa3ff9e87e0fdba7097e3bfb5e02e450ca1e1cf )
I tested the functionality locally and it works like a charm, the problem is than since I move the implementation to an actual testing server the ResetPassword page doesn't work anymore.
I marked as "public" the component in the index.js router file like this:
{
path: '/ResetPassword/:token',
name: 'ResetPassword',
component: ResetPassword,
meta: {
public: true
}
}
plus I'm using Vue-Router in my component to allow it to be exposed (here's just the beginning of the component):
<script>
import axios from "axios";
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default {
name: 'ResetPassword',
props: {
token: String
},
[...]
The ResetPassword page doesn't even seem to be rendered while clicking the link and it appears entirely blank on the screen. The error "Uncaught SyntaxError: Unexpected token '<'" is displayed referred to the manifest file and here's the error that pops-up when I look at the console in the browser:
console error
The routing configuration is set to "historymode" at the moment and I also implemented a fallback method to redirect towards our homepage.
Does anyone have an idea why this is happening? Am I missing something? I know Vue JS allows to only create some kind of "Single Page Applications", but I thought exposing a public component like I described could be feasible.
Thanks so much to everyone in advance.
UPDATE:
Here follows the main.js file requested in the comments below:
import App from './App'
import BackToTop from './components/BackToTopComponent'
import BootstrapVue from 'bootstrap-vue'
import Cookies from 'vue-cookies'
import router from './router'
import Vue from 'vue'
import VueMoment from 'vue-moment'
import VueSession from 'vue-session'
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
const moment = require('moment')
require('moment/locale/it')
Vue.use(BootstrapVue)
Vue.use(Cookies)
Vue.use(VueSession)
Vue.use(VueMoment, { moment })
Vue.filter('siNo', value => (value ? 'Si' : 'No'))
Vue.config.productionTip = false
Vue.component('BackToTop', BackToTop)
Vue.prototype.$eventBus = new Vue()
Vue.prototype.$baseUrl = '{baseUrl}';
new Vue({
el: '#app',
router,
components: { App, BackToTop },
template: '<App/>'
})
I faced the same issue in my project!
Unable to acess links (copying and pasting) whitin my Site : Node.js - Express.js - Webpack - Vue.js - historymode
The problem was related to my weback.prod.conf.js file.
Try to add this info to your "output" attribue in your webpack conf file :
publicPath: '/'
you should have something like this :
output: {
publicPath: '/'
}

Importing js to Vue project

I'm looking at using Vuefire to make integrating Firestore with my Vue project easier. When reading the getting started documentation, they have you create a db.js file so that you can "conveniently" import it anywhere in your project.
import firebase from 'firebase/app'
import 'firebase/firestore'
// Get a Firestore instance
export const db = firebase
.initializeApp({ projectId: 'MY PROJECT ID' })
.firestore()
// Export types that exists in Firestore
// This is not always necessary, but it's used in other examples
const { Timestamp, GeoPoint } = firebase.firestore
export { Timestamp, GeoPoint }
// if using Firebase JS SDK < 5.8.0
db.settings({ timestampsInSnapshots: true })
On the next step in the Binding page they show you can import that module into a "RecentDocuments" component
// RecentDocuments.vue
import { db } from './db'
export default {
data() {
return {
documents: [],
}
},
firestore: {
documents: db.collection('documents'),
},
}
If I import that same db.js file into another component, won't it create another instance of the firebase firestore object, because it's basically calling .initializeApp again?
// SomeOtherComponent.vue
import { db } from './db'
export default {
...
Or am I not understanding how imports work?
No, it won't. Imports only happen once. The exports that come from each import are effectively singletons. You should be able to verify this by simply adding log messages to the import.

Relay's Inject Network Layer Not Being Recognized as a Function in a React App

I am following along a Lynda.com tutorial called "Building and Deploying a Full-Stack React Application", and in the chapter "Injecting the Relay Network Layer" there is in index.js, an attempt to set up a network layer, and the program compiles successfully but I'm receiving the following error in the browser:
TypeError: __WEBPACK_IMPORTED_MODULE_4_react_relay___default.a.injectNetworkLayer is not a function
Any ideas?
I'd appreciate it,
CM
(My index.js file)
import React from 'react'
import ReactDOM from 'react-dom'
import {Router, browserHistory, applyRouterMiddleware} from 'react-router'
import Routes from './routes'
import Relay from 'react-relay'
import useRelay from 'react-router-relay'
import {RelayNetworkLayer, urlMiddleware} from 'react-relay-network-layer'
import {relayApi} from './config/endpoints'
import auth from './utils/auth'
const createHeaders = () => {
let idToken = auth.getToken()
if (idToken) {
return {
'Authorization': `Bearer ${idToken}`
}
} else {
return {}
}
}
Relay.injectNetworkLayer(
new RelayNetworkLayer([
urlMiddleware({url: (req) => relayApi,}),
next => req => {
req.headers = {
...req.headers,
...createHeaders()
}
return next(req)
},
],{disableBatchQuery: true})
)
ReactDOM.render(
<Router
environment={Relay.Store}
render={applyRouterMiddleware(useRelay)}
history={browserHistory}
routes={Routes}
/>,
document.getElementById('root')
)
You are probably not using the right version of Relay, but its just a guess. Check if the tutorial specifies any version and check which one you are using.
A lot of things changed in the last version of Relay: Relay-Modern. You might want to look into that, its way more convenient and efficient than Relay-Classic.
Also there are easier ways to combine a router with relay. Create your Relay Environment directly above or below your router, depending on if you need to get routes out of your db. But I guess you just need to get through the tutorial.

Categories

Resources