Oidc Client Sign in with Username and password - reactjs

I have a login form which have username and password fields in it. I want to authenticate username and password with Oidc Client . This is a method that was used for signing in by default:
async signIn(state) {
await this.ensureUserManagerInitialized();
try {
const silentUser = await this.userManager.signinSilent(this.createArguments());
this.updateState(silentUser);
return this.success(state);
} catch (silentError) {
// User might not be authenticated, fallback to popup authentication
console.log("Silent authentication error: ", silentError);
try {
if (this._popUpDisabled) {
throw new Error('Popup disabled. Change \'AuthorizeService.js:AuthorizeService._popupDisabled\' to false to enable it.')
}
const popUpUser = await this.userManager.signinPopup(this.createArguments());
this.updateState(popUpUser);
return this.success(state);
} catch (popUpError) {
if (popUpError.message === "Popup window closed") {
// The user explicitly cancelled the login action by closing an opened popup.
return this.error("The user closed the window.");
} else if (!this._popUpDisabled) {
console.log("Popup authentication error: ", popUpError);
}
// PopUps might be blocked by the user, fallback to redirect
try {
await this.userManager.signinRedirect(this.createArguments(state));
return this.redirect();
} catch (redirectError) {
console.log("Redirect authentication error: ", redirectError);
return this.error(redirectError);
}
}
}
}
Method was called from Login.js :
async login(returnUrl) {
const state = {returnUrl };
const result = await authService.signIn(state);
switch (result.status) {
case AuthenticationResultStatus.Redirect:
break;
case AuthenticationResultStatus.Success:
await this.navigateToReturnUrl(returnUrl);
break;
case AuthenticationResultStatus.Fail:
this.setState({ message: result.message });
break;
default:
throw new Error(`Invalid status result ${result.status}.`);
}
}
Now i have a custom login form. I will have value of user-entered username and password but I have no idea of authenticating it. How can it be done?

Unfortunately it's not supported by the library yet.
https://github.com/IdentityModel/oidc-client-js/issues/234

Related

Change authentification error message text

I've followed the guide error-handling for handling back an error to the users from the setCredentials method. However, even when using the provided example method to throw an error to the user, I still get the generic error on all my reports:
This is the default code I used for setting up the setCredentials function looker-studio auth connector.
function setCredentials(request) {
try {
Logger.log('setCredentials/try');
var creds = request.userPass;
var username = creds.username;
var password = creds.password;
var validCreds = validateCredentials(username, password).validCreds;
if (!validCreds) {
return {
errorCode: 'INVALID_CREDENTIALS'
};
};
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('connector.username', username);
userProperties.setProperty('connector.password', password);
return {
errorCode: 'NONE'
};
} catch(e) {
Logger.log('setCredentials/catch');
DataStudioApp.createCommunityConnector()
.newUserError()
.setDebugText('Error setting credentials. Exception details: ' + e)
.setText('I want to show a custom error message')
.throwException();
}
}
This is the toast message I want to change
I tried to throw an error before returning INVALID_CREDENTIALS so it falls in the catch. However, I don't see changes in the text.
function setCredentials(request) {
try {
Logger.log('setCredentials/try');
var creds = request.userPass;
var username = creds.username;
var password = creds.password;
var validCreds = validateCredentials(username, password).validCreds;
if (!validCreds) {
throw new Error('Only to fall to the catch');
};
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('connector.username', username);
userProperties.setProperty('connector.password', password);
return {
errorCode: 'NONE'
};
} catch(e) {
Logger.log('setCredentials/catch');
throw new Error('This message appears but it doesn't overwritte the default message');
}
}
(I have admin set to true)
If I throw again a new Error in the catch before the DataStudioApp newUserError I can see that 2 error toasts appear. A default one and mine, however this is not the intended result. What I want is to edit the default error message and I don't know if it's possible.

CORS error while trying to access Flask API

I have a React front end and Flask Backend. There's a Long-Running Task in the Back end which is gonna start when I submit the Job from the Front end. I assigned 2 Buttons on the front end to Submit the Job and the Other One to Check the status of the Job and Retrieve Data if the Job Is Finished.
Front End Job Submit Function
const sendSubmitRequest = async () => {
try {
const resp = await axios.get('http://localhost:8000/submit-job/'+embedId);
if (resp.status === 202) {
setTaskId(resp.data.task_id)
console.log(resp.data);
alert("Job Submision Success..")
console.log("Job Submitted Successfully...")
} else {
alert("Job Submision Failed... \nCheck If the Video URL Is Correct")
}
} catch (err) {
// Handle Error Here
console.error(err);
}
};
Front End Check Job Status Function
const checkJobStatusTime = async () => {
let refreshId = null
try {
const refreshId = setInterval(async () => {
const resp = await axios.get('http://localhost:8000/get-result/'+taskId);
if (resp.status === 200 && resp.data.status === 'success') {
const resl = resp.data.result;
console.log(resl)
setData(resl);
alert("Data Retrieved Successfully...")
clearInterval(refreshId);
}
else if(resp.status === 200 && resp.data.status === 'not_found') {
clearInterval(refreshId);
} else {
console.log("Job Still Runing...")
}
}, 3000);
} catch(e) {
console.log(e);
clearInterval(refreshId);
}
}
In the Flask Back End, I have 2 Functions corresponds to the 2 Front End Functions
Backend Handle Job Submit Function
#app.route('/submit-job/<video_id>')
#cross_origin(origin='*', headers=['Content-Type', 'Authorization'])
def handle_submit(video_id):
job_id = id_generator()
executor.submit_stored(job_id, test_func, video_id)
return jsonify({'status': 'success', 'task_id': job_id, 'message': 'Job Submitted Successfully'}), 202
Backend Handle Check Job Status Function
#app.route('/get-result/<task_id>')
#cross_origin(origin='*', headers=['Content-Type', 'Authorization'])
def get_result(task_id):
if task_id in executor.futures._futures.keys():
if executor.futures.done(task_id):
future = executor.futures.pop(task_id)
return jsonify({'status': 'success',
'message': 'Job Completed Successfully',
'result': future.result()}), 200
else:
return jsonify({'status': executor.futures._state(task_id),
'message': 'Job Still Running',
'result': None}), 200
else:
return jsonify({'status': 'not_found',
'message': 'Task Id Cannot be Found.',
'result': None}), 200
Import 'cross_origin'
from flask_cors import cross_origin
PROBLEM:
When I Assigned the 2 Functions to the 2 Buttons Separately Everything works fine As Expected. However, If I try to call the Check status Function with the Job submit Function Like this,
const sendSubmitRequest = async () => {
try {
const resp = await axios.get(endPoint+'/youtube/submit-job/'+embedId);
if (resp.status === 202) {
setTaskId(resp.data.task_id);
console.log("Job Submitted Successfully...")
// Calling the Status Check Function
checkJobStatusTime();
} else {
alert("Job Submision Failed... \nCheck If the Video URL Is Correct")
}
} catch (err) {
// Handle Error Here
console.error(err);
}
};
This gives the CORs error.
Access to XMLHttpRequest at 'http://localhost:8000/get-result/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Can someone help me figure out why this is Happening?
Try to use the #cross_origin decorator without any arguments.
As it's written in the Documentation:
In the simplest case, simply use the default parameters to allow all origins in what is the most permissive configuration
Also headers is not a valid parameter for this decorator.
You might want to use allow_headers.

how to redirect after authentication using oidc client in react app

I am trying to do authentication using identity server 4 for my react app.i followed this documentation.I am using implicit flow of identity server so onload application it will go to login page of identity server. after giving proper username and password it will validate and give a token.Everything is working as expected but i am not able to redirect my react app to Dashboard page.I am very new to react please help me.
// Copyright (c) Microsoft. All rights reserved.
import Config from 'app.config';
import AuthenticationContext from 'adal-angular/dist/adal.min.js'
import { Observable } from 'rxjs';
import { HttpClient } from 'utilities/httpClient';
import { toUserModel, authDisabledUser } from './models';
import Oidc, { User } from 'oidc-client';
const ENDPOINT = Config.serviceUrls.auth;
export class AuthService {
//static authContext; // Created on AuthService.initialize()
//static authEnabled = true;
//static aadInstance = '';
//static appId = '00000000-0000-0000-0000-000000000000';
//static tenantId = '00000000-0000-0000-0000-000000000000';
//static clientId = '00000000-0000-0000-0000-000000000000';
static initialize() {
if (typeof global.DeploymentConfig === 'undefined') {
alert('The dashboard configuration is missing.\n\nVerify the content of webui-config.js.');
throw new Error('The global configuration is missing. Verify the content of webui-config.js.');
}
if (typeof global.DeploymentConfig.authEnabled !== 'undefined') {
AuthService.authEnabled = global.DeploymentConfig.authEnabled;
if (!AuthService.authEnabled) {
console.warn('Auth is disabled! (see webui-config.js)');
}
}
//AuthService.tenantId = global.DeploymentConfig.aad.tenant;
//AuthService.clientId = global.DeploymentConfig.aad.appId;
//AuthService.appId = global.DeploymentConfig.aad.appId;
//AuthService.aadInstance = global.DeploymentConfig.aad.instance;
if (AuthService.aadInstance && AuthService.aadInstance.endsWith('{0}')) {
AuthService.aadInstance = AuthService.aadInstance.substr(0, AuthService.aadInstance.length - 3);
}
// TODO: support multiple types/providers
if (AuthService.isEnabled() && global.DeploymentConfig.authType !== 'aad') {
throw new Error(`Unknown auth type: ${global.DeploymentConfig.authType}`);
}
//AuthService.authContext = new AuthenticationContext({
// instance: AuthService.aadInstance,
//tenant: AuthService.tenantId,
//clientId: AuthService.clientId,
//redirectUri: "http://localhost:3000/dashboard",
//expireOffsetSeconds: 300, // default is 120
//postLogoutRedirectUri: window.location.protocol
//});
}
static isDisabled() {
return AuthService.authEnabled === false;
}
static isEnabled() {
return !AuthService.isDisabled();
}
static onLoad(successCallback) {
debugger;
AuthService.initialize();
if (AuthService.isDisabled()) {
console.debug('Skipping Auth onLoad because Auth is disabled');
if (successCallback) successCallback();
return;
};
var config = {
authority: "http://localhost:5000",
client_id: "mvc",
redirect_uri: "http://localhost:3000/dashboard",
response_type: "id_token token",
post_logout_redirect_uri : "http://localhost:5003/index.html",
};
var mgr = new Oidc.UserManager(config);
mgr.signinRedirect();
mgr.getUser().then(function(user){
if(user){
console.log("User logged in", user.profile);
}
else {
console.log("User not logged in");
}
});
mgr.events.addUserLoaded(function(userLoaded){
mgr.User=userLoaded;
})
mgr.events.addSilentRenewError(function (error){
console.log('the user has signrd out');
mgr._user=null;
})
//mgr.login();
//mgr.renewToken();
// Note: "window.location.hash" is the anchor part attached by
// the Identity Provider when redirecting the user after
// a successful authentication.
// if (AuthService.authContext.isCallback(window.location.hash)) {
// console.debug('Handling Auth Window callback');
// // Handle redirect after authentication
// AuthService.authContext.handleWindowCallback();
// const error = AuthService.authContext.getLoginError();
// if (error) {
// throw new Error(`Authentication Error: ${error}`);
// }
// } else {
// AuthService.getUserName(user => {
// if (user) {
// console.log(`Signed in as ${user.Name} with ${user.Email}`);
// if (successCallback) successCallback();
// } else {
// console.log('The user is not signed in');
// AuthService.authContext.login();
// }
// });
// }
}
static getUserName(callback) {
if (AuthService.isDisabled()) return;
if (AuthService.authContext.getCachedUser()) {
Observable.of({ Name:AuthService.authContext._user.userName, Email: AuthService.authContext._user.userName })
.map(data => data ? { Name: data.Name, Email: data.Email } : null)
.subscribe(callback);
} else {
console.log('The user is not signed in');
AuthService.authContext.login();
}
}
/** Returns a the current user */
static getCurrentUser() {
if (AuthService.isDisabled()) {
return Observable.of(authDisabledUser);
}
return HttpClient.get(`${ENDPOINT}users/current`)
.map(toUserModel);
}
static logout() {
if (AuthService.isDisabled()) return;
AuthService.authContext.logOut();
AuthService.authContext.clearCache();
}
/**
* Acquires token from the cache if it is not expired.
* Otherwise sends request to AAD to obtain a new token.
*/
static getAccessToken() {
debugger;
if (AuthService.isDisabled()) {
return Observable.of('client-auth-disabled');
}
return Observable.create(observer => {
return AuthService.authContext.acquireToken(
AuthService.appId,
(error, accessToken) => {
if (error) {
console.log(`Authentication Error: ${error}`);
observer.error(error);
}
else observer.next(accessToken);
observer.complete();
}
);
});
}
}
The problem i am facing is after authentication my app is going some kind of loop means the url of app is changing to identity server and local app url.you can see my app was using AuthenticationContext from adal previously.i want to change into oidc for identity server4.
I see that you mentioned redirect uri as dashboard? 'redirect_uri: "http://localhost:3000/dashboard'. So from the Identity server, the user will be redirected here right? Can you show us what you are doing on the dashboard page?
Typically, in Identity server implementation, redirect Uri needs to be a simple page whose responsibility needs to be nothing but accessing the Tokens from the URL and redirecting to the desired page (like redirecting to the dashboard from here)
I understand what I gave you is more of a theoretical answer, but seeing your implementation of redirect URL help you get a better answer.

How to know user is already login at another browser in firebase

I have reactjs admin panel for my project admin module. I have requirement that is if 2 user have same userId and password then both of them can not login in same time. If User1 already has logged into admin panel then User2 should not be login. I have get Id token of logged in user and saved it into database now I wanted to check whether the user is already login or not.
I dont have any idea how to prevent user to login in admin panel if other user is already logged in.
Please show some light on code and suggest me right path to fulfill my requirement
Here is my code:
//AUTHENTICATION
var loggedIn = false;
var activeSession = true;
if (Config.firebaseConfig.apiKey) {
firebase.auth().onAuthStateChanged(function (user) {
// Retriving ID Token
var Auth = firebase.auth();
var idToken = Auth.currentUser.getToken();
firebase.database().ref('activeSession').push({
idToken:idToken,
userEmail : user.email,
userId: user.uid,
isUserLoggedIn : activeSession
});
firebase.auth().verifyIdToken(idToken).then(function(decodedToken) {
console.log(decodedToken);
var uid = decodedToken.uid;
console.log(uid);
// ...
}).catch(function(error) {
// Handle error
});
}).catch(function(error) {
// Handle error
console.log(error);
});
if (user) {
// User is signed in.
console.log("User is signed in " + user.email);
if (Config.adminConfig.allowedUsers != null && Config.adminConfig.allowedUsers.indexOf(user.email) == -1) {
//Error, this user is not allowed anyway
alert("The user " + user.email + " doens't have access to this admin panel!");
firebase.auth().signOut();
} else {
loggedIn = true;
displayApp();
}
} else {
// No user is signed in.
console.log("No user is signed in ");
loggedIn = false;
displayApp();
if (window.display) {
window.display();
}
}
} else {
// No user is signed in.
console.log("No user is signed in, step 1 ");
loggedIn = false;
displayApp();
if (window.display) {
window.display();
}
}
function displayApp() {
if (loggedIn) {
ReactDOM.render(
<Admin />,
document.getElementById('root')
);
} else {
ReactDOM.render(
<Login />,
document.getElementById('root')
);
}
}
displayApp();

How do i check if user is admin using jwt on sailsjs

I'm using the sailsjs framework on my server side and angularjs on my front end to build a SPA and using jsonwebtoken to do token authentication. My user api has the information: name: string, email: email, admin: Boolean, which are the information I use to generate the token and send to the front end save in localstorage.
My question is: how could I do to verify (check if the token is valid already is ready and everything is working) if the user is admin on my server-side?
Thank you in advance.
Below my current policy to check the token on the server-side
module.exports = function(req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return res.json(401, {
err: 'Format is Authorization: Bearer [token]'
});
}
} else if (req.param('token')) {
token = req.param('token');
// We delete the token from param to not mess with blueprints
delete req.query.token;
} else {
return res.json(401, {
err: 'No Authorization header was found'
});
}
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) {
console.log('ERR estou em tokenauth policies');
return res.json(401, {
err: 'The token is not valid'
});
}
req.token = token;
next();
});
};
Do 3 policies:
SetJwt: `req.
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) {
console.log('ERR estou em tokenauth policies');
return res.json(401, {
err: 'The token is not valid'
});
} else req.token = token
}
isAdmin:
if (req.auth === ADMIN_LEVEL) next()
else res.forbidden()
isUser:
if (req.auth === USER_LEVEL) next()
else res.forbidden()
Your policies:
someControllerMethod: [setJwt, isAdmin]
Of course you need to add an int or even a flag isadmin in your database for this to work. And the token needs to hold this information!

Resources