I'm trying to authenticate a user with Discord oauth2, then add this user to the guild. I'm also using Passportjs to authenticate the user, so the DiscordStrategy follows as
#Injectable()
export class DiscordStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
clientID: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
callbackURL: `http://${process.env.HOST}:${process.env.PORT}/auth/discord/callback`,
scope: ['identify', 'guilds', 'guilds.join'],
});
}
async validate(accessToken: string, refreshToken: string, profile: Profile) {
const { id } = profile;
console.log(profile);
const resp = await this.authService.joinGuild(accessToken, id);
console.log(resp);
}
}
and the authService.joinGuild
async joinGuild(accessToken: string, userId: string) {
return this.httpService
.put(
`https://discord.com/api/v8/guilds/${process.env.DISCORD_GUILD_ID}/members/${userId}`,
{
headers: {
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN}`,
},
body: {
access_token: `${accessToken}`,
},
},
)
.pipe(
catchError((e) => {
throw new HttpException(e.response.data, e.response.status);
}),
)
.pipe(
map((res) => {
console.log(res.data);
return res.data;
}),
)
.toPromise();
}
and my response data is data: { message: '401: Unauthorized', code: 0 }
What am I doing wrong here? I tried to give my bot every permission possible as well. Thanks.
Related
when the account login endpoint localhost:5000/login a successful message appears, but when I call localhost:5000/status an error message '401' Unauthorized appears as if the login session was not saved
Here My Backend controllers/Auth.js
export const Status = async(req, res) =>{
if(!req.session.userId){
return res.status(401).json({msg: "Mohon login terlebih dahulu"});
}
const user = await User.findOne({
attributes: ['uuid', 'name', 'email', 'number','role'],
where: {
uuid: req.session.userId
}
});
if (!user) return res.status(400).json({msg: "User Tidak Ada"});
res.status(200).json(user);
}
Here My Frontend Auth.vue
import axios from 'axios';
export default{
namespace: true,
state: {
uuid: null,
user: null,
},
mutations: {
SET_UUID(state, uuid){
state.uuid = uuid
},
SET_USER(state, data){
state.user = data
}
},
actions: {
async signIn({ dispatch }, credentials){
let response = await axios.post('login', credentials)
dispatch('attempt', response.data.uuid)
},
async attempt({ commit }, uuid){
commit('SET_UUID', uuid)
try {
let response = await axios.get('status',{
headers: {
'Authorization': 'Bearer ' + uuid
}
})
commit('SET_USER', response.data)
} catch (error) {
commit('SET_UUID', null);
commit('SET_USER', null);
}
}
},
}
My Route route/AuthRoute.js
import express from "express";
import {
Login,
Status,
logOut
} from "../controllers/Atuh.js";
const router = express.Router();
router.get("/status", Status);
router.post("/login", Login);
router.delete("/logout", logOut);
export default router;
I have used next-auth for Authentication in my next.js project and have deployed it on AWS server using DOcker. I am getting "http://localhost:3000/api/auth/error?error=Something%20went%20wrong!%20Please%20try%20again%20later." in responce of network everytime when I try to login or register and on all the pages where I have uset nextauth.
This is my nextauth code:
[...nextauth.js]
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { API_BASE_URL } from '../../../utils/constants';
export default NextAuth({
providers: [
CredentialsProvider({
id: 'credentials',
name: 'Busfabrik',
credentials: {
email_id: {
label: 'email',
type: 'email',
},
password: { label: 'Password', type: 'password' }
},
async authorize(credentials, req) {
const payload = {
email_id: credentials.email_id,
password: credentials.password,
isadmin: !!credentials.isadmin
};
const res = await fetch(API_BASE_URL + '/users/login', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
},
});
const user = await res.json();
// console.log('user', user);
// If error and we don't have user data, return error
if (!res.ok) {
throw new Error(user.exception);
}
// If no error and we have user data, return it
if (res.ok && user.success) {
return user;
} else {
// Return error if user data could not be retrieved
throw new Error(user.msg);
}
},
}),
// ...add more providers here
],
secret: process.env.JWT_SECRET,
callbacks: {
async jwt({ token, user }) {
// console.log('jwt user', user)
if (user && user.success) {
return {
...token,
accessToken: user.payload.token,
userData: user.payload
};
}
return token;
},
async session({ session, token }) {
// console.log('session', session);
// console.log('session token', token);
session.accessToken = token.accessToken;
session.user = token.userData;
return session;
},
},
theme: {
colorScheme: 'auto', // "auto" | "dark" | "light"
brandColor: '', // Hex color code #33FF5D
logo: '/vercel.svg', // Absolute URL to image
},
// Enable debug messages in the console if you are having problems
debug: process.env.NODE_ENV === 'development',
});
Can someone suggest or have aced the same issue? If Yes, then please guide me on this. I an stuck here from a long time and not able to find the solution.
I am trying to implement NextAuth with Credentials (email and password).
I have set up my mongodb for this. I also set up /api/proile/ route to post login credentials and tested it out with Postman, returns user correctly.
But the problem starts with after logging in. when I log in, credentials return in the vscode terminal (I console log in /api/auth/[...nextauth].js with console.log(credentials) but in the browser it authorizes the user, i can access and view protected routes and stuff, but when I log the session in front-end, it displays as null for user information as you can see in the picture below;
here is my /api/auth/[...nextauth].js code;
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
import { connectToDatabase } from '../../../util/mongodb';
const options = {
providers: [
Providers.Credentials({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'text' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
console.log(credentials);
const res = await fetch('http://localhost:3000/api/profile/', {
method: 'POST',
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json',
},
});
const user = await res.json();
// const user = { id: '1', name: 'Suat Bayrak', email: 'test#test.com2' };
if (user) {
return user;
} else {
return null;
}
},
}),
],
pages: {
signIn: '/signin',
},
session: {
jwt: true,
maxAge: 30 * 24 * 60 * 60,
updateAge: 24 * 60 * 60,
},
database: `mongodb+srv://${process.env.MONGO_DB_USERNAME}:${process.env.MONGO_DB_PASSWORD}#nextjs-academia- sb.ki5vd.mongodb.net/test`,
};
export default (req, res) => NextAuth(req, res, options);
by the way, when I use static user credentials like i commented in the code above, it works perfectly fine and returns session info correctly...
Also here is my /pages/signin.js
import { signIn } from 'next-auth/client';
import { useState } from 'react';
import { useRouter } from 'next/router';
export default function SignIn() {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loginError, setLoginError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
console.log('submitted!');
signIn('credentials', {
email: email,
password: password,
// email: 'test#test.com',
// password: '1234',
callbackUrl: 'http://localhost:3000/about',
redirect: false,
}).then(function (result) {
console.log(result);
if (result.error !== null) {
if (result.status === 401) {
setLoginError(
'Your username/password combination was incorrect. Please try again'
);
} else {
setLoginError(result.error);
}
} else {
console.log(result);
router.push(result.url);
}
});
};
return (
<form onSubmit={handleSubmit}>
<label>
Email
<input
name='email'
type='text'
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<label>
Password
<input
name='password'
type='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</label>
<button type='submit'>Sign in</button>
</form>
);
}
also here is my github repo for this whole code;
GitHub Repo
UPDATE: At first login, user info displays on the terminal but after I refresh the page, it says undefined
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
const options = {
providers: [
Providers.Credentials({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'text' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
console.log(credentials);
let user;
const res = await fetch('http://localhost:3000/api/profile/', {
method: 'POST',
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json',
},
});
const arrayToJson = await res.json();
user = arrayToJson[0];
if (user) {
return user;
} else {
return null;
}
},
}),
],
pages: {
signIn: '/signin',
},
session: {
jwt: true,
maxAge: 30 * 24 * 60 * 60,
updateAge: 24 * 60 * 60,
},
callbacks: {
async signIn(user) {
return user.userId && user.isActive === '1';
},
async session(session, token) {
session.user = token.user;
return session;
},
async jwt(token, user) {
if (user) token.user = user;
return token;
},
},
database: `mongodb+srv://${process.env.MONGO_DB_USERNAME}:${process.env.MONGO_DB_PASSWORD}#nextjs-academia-sb.ki5vd.mongodb.net/test`,
};
export default (req, res) => NextAuth(req, res, options);
so the problem was at callbacks section of the code. Now its working fine
the Authorization header is always undefined when I am trying to login. Tried setting AOT = false in my angular.json file but to no avail. What is the issue here?
Auth-Interceptor
import { HttpHandler, HttpInterceptor, HttpRequest } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { AuthService } from "./auth.service";
#Injectable()
export class AuthInterceptor implements HttpInterceptor{
constructor(private authService: AuthService){}
intercept(req: HttpRequest<any>, next: HttpHandler){
const authToken = this.authService.getToken();
const authRequest = req.clone({
headers: req.headers.set("Authorization", "Bearer " + authToken)
})
return next.handle(authRequest)
}
}
checkAuth middleware on backend
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
try{
const token = req.headers.authorization.split(" ")[1]
jwt.verify(token, "asderfghtyu")
next();
}
catch(error) {
res.status(401).json({
message: "Authorization failed macha"
})
}
}
auth-service.ts
export class AuthService {
private token: string;
constructor(private http: HttpClient) { }
getToken(){
return this.token;
}
createUser(FullName: string, email: string, role: string, password: string) {
const authData: AuthData = { FullName: FullName, email: email, role: role, password: password }
this.http.post("http://localhost:3300/api/user/signup", authData)
.subscribe(result => {
console.log(result);
})
}
login(email: string, password: string){
this.http.post<{token: string}>("http://localhost:3300/api/user/login", {email: email, password: password})
.subscribe(response=>{
const token = response.token;
this.token = token;
})
}
Here is the auth-service.ts file where getToken() function is present
In your Auth-Interceptor, replace -
const authRequest = req.clone({
headers: req.headers.set("Authorization", "Bearer " + authToken)
})
with -
const authRequest = !authToken ? req : req.clone({
setHeaders: { Authorization: `Bearer ${authToken}` }
});
This will add an Authorization header only if you have a token. If authService.getToken() returns undefined, no Authorization header will be added to the request.
I try to make authorization and permissions availlable with react-admin and a Node server:https://github.com/hagopj13/node-express-mongoose-boilerplate
For react-admin there is an exemple of code: https://marmelab.com/react-admin/Authorization.html#configuring-the-auth-provider
// in src/authProvider.js
import decodeJwt from 'jwt-decode';
export default {
login: ({ username, password }) => {
const request = new Request('https://example.com/authenticate', {
method: 'POST',
body: JSON.stringify({ username, password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ token }) => {
const decodedToken = decodeJwt(token);
localStorage.setItem('token', token);
localStorage.setItem('permissions', decodedToken.permissions);
});
},
logout: () => {
localStorage.removeItem('token');
localStorage.removeItem('permissions');
return Promise.resolve();
},
checkError: error => {
// ...
},
checkAuth: () => {
return localStorage.getItem('token') ? Promise.resolve() : Promise.reject();
},
getPermissions: () => {
const role = localStorage.getItem('permissions');
return role ? Promise.resolve(role) : Promise.reject();
}
};
But i don't understand how it work and on login the server return an user object like this:
{user: {id: "5e429d562910776587c567a2", email: "admin#test.com", firstname: "Ad", lastname: "Min",…},…}
tokens: {access: {,…}, refresh: {,…}}
access: {,…}
expires: "2020-03-03T06:45:10.851Z"
token: "eyJhbGciOi..."
refresh: {,…}
expires: "2020-04-02T06:15:10.851Z"
token: "eyJhbGciOi..."
user: {id: "5e429d562910776587c567a2", email: "admin#test.com", firstname: "Ad", lastname: "Min",…}
createdAt: "2020-02-11T12:25:58.760Z"
email: "admin#test.com"
firstname: "Ad"
id: "5e429d562910776587c567a2"
lastname: "Min"
role: "admin"
updatedAt: "2020-02-11T12:25:58.760Z"
There are already tokens and role and in the server, it seems to have a permission control:
role.js
const roles = ['user', 'admin'];
const roleRights = new Map();
roleRights.set(roles[0], []);
roleRights.set(roles[1], ['getUsers', 'manageUsers']);
module.exports = {
roles,
roleRights,
};
And the auth.js
const passport = require('passport');
const httpStatus = require('http-status');
const AppError = require('../utils/AppError');
const { roleRights } = require('../config/roles');
const verifyCallback = (req, resolve, reject, requiredRights) => async (err, user, info) => {
if (err || info || !user) {
return reject(new AppError(httpStatus.UNAUTHORIZED, 'Please authenticate'));
}
req.user = user;
if (requiredRights.length) {
const userRights = roleRights.get(user.role);
const hasRequiredRights = requiredRights.every(requiredRight => userRights.includes(requiredRight));
if (!hasRequiredRights && req.params.userId !== user.id) {
return reject(new AppError(httpStatus.FORBIDDEN, 'Forbidden'));
}
}
resolve();
};
const auth = (...requiredRights) => async (req, res, next) => {
return new Promise((resolve, reject) => {
passport.authenticate('jwt', { session: true }, verifyCallback(req, resolve, reject, requiredRights))(req, res, next);
})
.then(() => next())
.catch(err => next(err));
};
module.exports = auth;
But how to get authorization and permission works from the react-admin?
Thanks & Regards
Ludo
In react-admin there is a usePermissions() hook, which calls the authProvider.getPermissions() method on mount. This method return to you single string value like 'admin' or string array of permissions like ['admin','crm'...]. This strings are up to you how to set. In example below it's storing in localStorage, but in real life need to extract it from JWT token or retrieve it from backend.
getPermissions: () => {
const role = localStorage.getItem('permissions');
return role ? Promise.resolve(role) : Promise.reject();
}
import { usePermissions } from 'react-admin';
in function
const { permissions } = usePermissions();
return (
{ permissions == 'admin' &&
<DashboardMenuItem primaryText="Dashboard" onClick={onMenuClick} sidebarIsOpen={open} />
}
...
);