How To login with Facebook using react? - reactjs

I have used "react-facebook-login" this package for login Facebook I
have got a response from Facebook and get token and then I forward
token to backend and the backend will be sending some JSON like
{userId: "1",sessionID: "2" successInd: "true"}
I want when I got a success is true then I go next page which is my dashboard page.
here is my code :-
class App extends Component {
constructor() {
super();
this.state = { isAuthenticated: false, user: null, token: ''};
}
logout = () => {
this.setState({isAuthenticated: false, token: '', user: null})
};
onFailure = (error) => {
alert(error);
};
twitterResponse = (response) => {
const token = response.headers.get('x-auth-token');
response.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token});
}
});
};
facebookResponse = (response) => {
const tokenBlob = new Blob([JSON.stringify({access_token: response.accessToken}, null, 2)], {type : 'application/json'});
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
cache: 'default'
};
fetch('http://localhost:4000/api/v1/auth/facebook', options).then(r => {
const token = r.headers.get('x-auth-token');
r.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token})
}
});
})
};

Related

MSAL can not get access token even the refresh token still valid

Hi I am using MSAL to manage the auth part in my app, I am using ADFS, the access token duration is 5min and the refresh token is 1 hour, the problem is that after each 5min, I got a 401 from backen telling me that the access token is expired, I am using acquireTokenSilent :
import {
InteractionRequiredAuthError,
PublicClientApplication,
} from '#azure/msal-browser';
import { authorized } from './request';
const msalConfig = new PublicClientApplication({
auth: {
clientId: process.env.REACT_APP_AUTH_CLIENT_ID || '',
authority: process.env.REACT_APP_AUTH_AUTHORITY,
knownAuthorities: [process.env.REACT_APP_AUTH_KNOWN_AUTHORITIES || ''],
redirectUri: process.env.REACT_APP_AUTH_REDIRECT_URI,
postLogoutRedirectUri: process.env.REACT_APP_AUTH_REDIRECT_URI,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
telemetry: {
application: {
appName: 'SOC',
appVersion: '1.0.0',
},
},
});
export const loginRequest = {
scopes: ['User.Read', 'openid'],
};
export const getToken = (instance) =>
new Promise((resolve, reject) => {
const accounts = instance.getAllAccounts();
if (accounts.length > 0) {
const request = {
...loginRequest,
account: accounts[0],
};
instance
.acquireTokenSilent(request)
.then((response) => {
resolve(response.accessToken);
authorized(response.accessToken);
})
.catch((error) => {
if (error instanceof InteractionRequiredAuthError) {
instance.acquireTokenRedirect(request);
}
reject('Error while acquiring the token');
});
}
});
export const getIdToken = (instance) => {
const accounts = instance.getAllAccounts();
if (accounts.length > 0) {
const request = {
...loginRequest,
account: accounts[0],
};
return instance.acquireTokenSilent(request).then((response) => {
return response?.idToken;
});
}
};
export default msalConfig;
after getting the access token I pass it in headers in api calls using axios :
import axios, { AxiosInstance } from 'axios';
import { AxiosConfigs } from './Configs';
import msalInstance, { getToken } from './authProvider';
const request: AxiosInstance = axios.create({
timeout: AxiosConfigs.TIMEOUT,
baseURL: AxiosConfigs.BASE_URL,
});
request.interceptors.request.use(
async (config) => {
// Do something before request is sent
const baseURL = AxiosConfigs.BASE_URL;
const tempConf = { ...config, baseURL };
let authorization = getAuthorization();
if (!authorization) {
await getToken(msalInstance);
tempConf.headers!.Authorization = getAuthorization();
}
return tempConf;
},
(error) => Promise.reject(error),
);
const authorized = (token) => {
request.defaults.headers.common['Authorization'] = `Bearer ${token}`;
return request;
};
const getAuthorization = () => {
return request.defaults.headers.common['Authorization'];
};
export default request;
export { authorized, getAuthorization };

NestJs Authentication Tutorial always returns 401 Unauthorized after implementing local strategy (When using browser)

What I want to do is a simple authentication using passport as this tutorial suggests: https://docs.nestjs.com/techniques/authentication
I followed this tutorial all along and works when i use Insomnia, Swagger or Postman. Later I created my front-end in react but the requests always returns
POST http://localhost:3333/auth/login 401 (Unauthorized)
{statusCode: 401, message: 'Unauthorized'}.
Other routes like /user/getAll work normally in swagger/postman and in the browser. But the auth route auth/login only works in swagger/postman
Am I missing something here?
I looking for a solution for 4 hours and all the solutions that I found did not work in my project.
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const corsOptions = {
origin: '*',
credentials: true,
allowedHeaders: 'Content-Type, Accept, Origin',
preflightContinue: false,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
};
app.enableCors(corsOptions);
app.use(helmet());
app.use(cookieParser());
// app.use(csurf());
const config = new DocumentBuilder()
.setTitle('Nyx Swagger')
.setDescription('The Nyx API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
app.useGlobalPipes(new ValidationPipe());
await app.listen(process.env.PORT || 3333);
}
bootstrap();
app.module.ts
#Module({
imports: [
MongooseModule.forRoot(
'mongodb+srv://USERNAME:PASSWORD#db-beta.6pfkk.mongodb.net/db-beta?retryWrites=true&w=majority',
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true,
},
),
ThrottlerModule.forRoot({
ttl: 60,
limit: 10,
}),
AuthModule,
UsersModule,
],
controllers: [AppController],
providers: [
LocalStrategy,
],
})
export class AppModule {}
app.controller.ts
#Controller()
export class AppController {
constructor(private authService: AuthService) {}
#UseGuards(LocalAuthGuard)
#Post('auth/login')
async login(
#Body() _: MakeAuthDto,
#Request() req,
#Res({ passthrough: true }) res,
) {
const access_token = await this.authService.login(req.user, req.ip);
res.cookie('jwt', access_token);
return req.user;
}
}
auth.module.ts
#Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: process.env.JWTSECRET,
signOptions: { expiresIn: '7d' },
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
auth.service.ts
#Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(email: string, pass: string): Promise<UserDocument | any> {
const user = await this.usersService.findOne({ email } as any, true);
if (
user &&
(await user.compareHash(pass)) &&
user.hasAccess &&
!user.deleted
) {
const {
password,
verificationCode,
ips,
deleted,
hasAccess,
usageTerms,
usageTermsHistory,
...result
} = user.toObject();
return result;
}
return null;
}
async login(user: UserDocument, ip: string): Promise<string> {
const payload = {
email: user.email,
sub: user._id,
name: user.name,
roles: user.roles,
};
await this.usersService.updateLastLogin(user._id, ip);
return this.jwtService.sign(payload);
}
}
jwt.strategy.ts
const cookieExtractor = function (req) {
let token = null;
if (req && req.cookies) {
token = req.cookies['jwt'];
}
return token;
};
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromExtractors([cookieExtractor]),
ignoreExpiration: false,
secretOrKey: process.env.JWTSECRET,
});
}
async validate(payload: any) {
return {
_id: payload.sub,
name: payload.name,
email: payload.email,
roles: payload.roles,
};
}
}
local.strategy.ts
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email' });
}
async validate(email: string, password: string): Promise<UserDocument> {
const user = await this.authService.validateUser(email, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
front-end request
export const AuthAPI = {
async login(data) {
const response = await fetch(`${API_URL}/auth/login`, {
method: "POST",
headers: { "Content-type": "application/json", accept: "*/*" },
// credentials: "include",
body: JSON.stringify(data),
});
const json = await response.json();
return json;
},
};
Prints:

How to return api errors to Login Component in NextAuth.js

How to return API errors to Login Component in NextAuth.js.Actually, I am trying to pass the Errors back to Login Component in NextAuth(Credentials Provider). I am getting this object in console error: "CredentialsSignin" ok: false status: 401 url: null [[Prototype]]: Object Everything is working fine like I am able to log in, but when I am trying to handle errors coming from APIs, I am unable to handle them.
[...nextauth.js] File
export default (req, res) =>
NextAuth(req, res, {
providers: [
CredentialsProvider({
authorize: async (credentials) => {
try {
const data = {
email: credentials.email,
password: credentials.password
}
const user = await login(data);
console.log("401 Error",user.data);
if (user.data.status==200) {
console.log("200 data",user.data);
return Promise.resolve(user.data);
}else if(user.data.status==401){
// Here I wants to Handle Errors and return them back to My login Compenent
}
} catch (error) {
if (error.response) {
console.log(error.response);
Promise.reject(new Error('Invalid Username and Password combination'));
}
}
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
pages: {
signIn: '/login',
},
callbacks: {
jwt: async ({token,user})=>{
if(user){
token.userid = user.id;
token.name = user.username;
token.token = user.token;
}
return token;
},
session: (session,token)=>{
return session;
}
},
secret:"test",
jwt:{
secret:"test",
encryption:true,
},
site: process.env.NEXTAUTH_URL || "http://localhost:3000",
session: {
jwt: true,
maxAge: 1 * 3 * 60 * 60, // 3 hrs
updateAge: 24 * 60 * 60, // 24 hours
}
});
const login = async data => {
var config = {
headers: {
'Content-Type': "application/json; charset=utf-8",
'corsOrigin': '*',
"Access-Control-Allow-Origin": "*"
}
};
const url = 'api/auth/login';
const result = await axios.post(url,data,config);
return result;
};
Login Components
const LoginSubmit = async (event) => {
event.preventDefault();
const enteredEmail = inputText.email;
const enteredPassword = inputText.password;
// console.log(enteredEmail);
const result = await signIn("credentials", {
redirect: false,
email: enteredEmail,
password: enteredPassword,
});
console.log("Final Result",result);
};
Yes you can do it :
Try :
// component.js
const res = await signIn("credentials", {
email: inputs.email,
password: inputs.password,
callbackUrl: `/`,
redirect: false,
});
if (res?.error) {
setLoading(false);
Swal.fire("Invalid Login", "username or password is incorrect");
}
and in Nextauth file you must throw an error if a user entred invalid credential!
//[...nextauth].js
const providers = [
Providers.Credentials({
name: "credentials",
authorize: async (credentials) => {
//statr try
try {
const user = await
axios.post(`${API_URL}/auth/local`, {
identifier: credentials.email,
password: credentials.password,
});
if (user) {
return { status: "success",
data:user.data };
}
} catch (e) {
throw new Error("Not found ");
}
},
}),
];

How do I resolve the issue of TypeError: Cannot read property 'then' of undefined?

I have a reactjs app that should be returning data from a WepAPI. The dispatch I call on a function seems to be giving me this error: TypeError: Cannot read property 'then' of undefined
I have used other functions through dispatch and it worked fine but this one still sticks out.
The intended result is for the data to get back to the initial dispatch. At the moment the data comes through but is stuck when returning to the initial call.
import React from 'react';
import { connect } from 'react-redux';
import { jobActions } from '../../actions/job.actions';
import Popup from 'reactjs-popup'
import JwPagination from 'jw-react-pagination';
class LoadTable extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
pagination: [],
Search: "Search",
sort: {
column: null,
direction: 'desc',
},
}
this.clearSearch = this.clearSearch.bind(this);
this.doSearch = this.doSearch.bind(this);
this.doSort = this.doSort.bind(this);
this.runLog = this.runLog.bind(this);
this.openRunLog = this.openRunLog.bind(this);
this.onChangePage = this.onChangePage.bind(this);
}
componentDidMount() {
this.props.getJobs()
.then((res) => {
this.setState({
data: res.results.response || []
})
});
}
clearSearch() {
this.props.getJobs()
.then((res) => {
this.setState({
data: res.results.response || [], Search: "Search",
sort: {
column: null,
direction: 'desc',
}
})
});
}
doSearch(e) {
const { name, value } = e.target;
this.setState({ [name]: value });
this.props.doSearch(value)<----Initial Call
.then((res) => {
this.setState({
data: res.results.response || [],
sort: {
column: null,
direction: 'desc',
}
})
});
}
render() {
return (
use data
)}
const mapDispatchToProps = dispatch => ({
getJobs: () => dispatch(jobActions.getJobs()),
doSearch(value) {
dispatch(jobActions.doSearch(value));<----dispatch
},
});
export default connect(mapStateToProps, mapDispatchToProps)(LoadTable);
==========================================
Action being called:
function doSearch(value) {
return (dispatch) => {
dispatch({ type: jobConstants.JOB_REQUEST });
return jobService.doSearch(value)
.then(
results => {
dispatch({ type: jobConstants.JOB_SUCCESS, user });
//Ran console logs and seen the results here
return { results };
},
error => {
dispatch({ type: jobConstants.JOB_FAILURE, error });
}
);
}
}
=========================
Services
function doSearch(SearchValue) {
const requestOptions = {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json; charset=utf-8'
}),
body: JSON.stringify({SearchValue})
};
const requestPath = 'http://localhost:53986/api/jobs/postsearch';
return fetch(requestPath, requestOptions)
.then(handleResponseToJson)
.then(response => {
if (response) {
return { response };
}
}).catch(function (error) {
return Promise.reject(error);
});
}
You need an async function for your service, which returns a promise. Like this
async function doSearch(val) {
const requestOptions = {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json; charset=utf-8'
}),
body: JSON.stringify({SearchValue})
};
const requestPath = 'http://localhost:53986/api/jobs/postsearch';
const data = fetch(requestPath, requestOptions);
const jsonData = await data.json();
return jsonData;
}
Then you can call like so:
doSearch(val).then() // and so on...
This is the pattern your looking for in this case.

React native fetch token and then get to user details using fetch api

I am building login app using React native. For auth, I am using spring boot app.
Here is use case.
User visit to client's login screen and enters username and password.
React native send request to the server using fetch API.
If the token object comes back then login (username/password) are correct.
If the token is correct app should make another call to the server to get user details by token.
Problem is - how I can first API call to validate login and get token and once get the valid token to make another API call to get user details.
Here is the code:
import { dologin,getUser } from "../../API";
And Login handeler
handleLogin = () => {
const { username, password } = this.state
if (username.length == 0 || password.length == 0){
this.setState({
errorMessage: 'Login and password is required.',
loginProcessing: false,
});
} else {
this.setState({errorMessage: null});
dologin(username, password).then(accessToken => {
if(!accessToken.state){
this.setState({
errorMessage: accessToken.data,
loginProcessing: false,
});
return null;
} else{
return accessToken.data;
}
});
}
}
Fetch API
//get user by token
export const getUser = (token) => {
if(token == null) return null;
return fetch('http://localhost:8080/api/user/get', {
method: 'GET',
headers: {"Authorization": "Bearer " + token}
}).then((response) => {
console.log(response.json());
return response.json();
}).catch((err) => {
console.log(err);
})
}
export const dologin = (username, password) => {
var details = {
username: username,
password: password,
grant_type:'password'
};
var formBody = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
return fetch('http://localhost:8080/oauth/token', {
method: 'POST',
headers: {
"Authorization": "Basic " + btoa("enrecover:EsTEsBDETSEWAvAWcsI"),
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: formBody.join("&")
}).then(res => {
if(res.status === 200){
return {status: true, data:res.json() }
} else {
return {status: false, data:"Invalid username or password." }
}
})
}
Make the handleLogin async function and try this one
handleLogin = async () => {
const { username, password } = this.state
if (username.length == 0 || password.length == 0) {
this.setState({
errorMessage: 'Login and password is required.',
loginProcessing: false,
});
} else {
let loginResponse = await dologin(username, password);
if (loginResponse.status) {
// if loginResponse = {token: "tokenValue"}
userDetails = await getUser(loginResponse.token);
console.log("User Details",userDetails)
} else {
this.setState({
errorMessage: loginResponse.data,
loginProcessing: false,
});
}
}
}

Resources