I'm using Auth0 with Angular 2. I have the following login code that don't go to the home page after authentication.
To my understanding, the auth0 will not do the redirection. It sends off authenticated event, and it should create an item in localstorage then navigate to the home page.
#Injectable()
export class AuthService {
lock = new Auth0Lock(this.config.clientID, this.config.domain, {
auth: {
responseType: 'token',
}
});
constructor(private http: Http, private config: AppConfig, private router: Router) {
// Add callback for lock `authenticated` event
this.lock.on('authenticated', (authResult) => {
localStorage.setItem('id_token', authResult.idToken);
console.log(localStorage);
this.router.navigate(['home']);
});
}
you can try location.replace('/home') or location.replace('http://localhost:4200/home')
Related
I try to use a NestJS backend with a Nginx reverse proxy.
I have coded an authentication part in my NestJS backend.
My problem is that when I used my frontend / backend in local mode, all is ok.
When I use it through Nginx, I always retrieve a 401 error.
I think it’s due to the LocalStrategy in NestJS
Here is the part in the local.strategy.ts file
import { Strategy } from 'passport-local';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { AuthService } from '../auth.service';
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
usernameField: 'userLogin',
passwordField: 'userPassword',
});
}
async validate(userLogin: string, userPassword: string): Promise<any> {
const user = await this.authService.validateUser(userLogin, userPassword);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Here is the part in the app.controller.ts file
#Public()
#UseGuards(LocalAuthGuard)
#Post('auth/login')
async login(#Request() req) {
return this.authService.login(req.user);
}
But I don’t know how to change it.
If somebody have an example it build be great.
Thanks in advance.
I've tested with curl locally on server (without nginx).
I saw my error (mysql access to test the user), it was not due to nginx configuration.
I have a VueJS single-page application and I use JWT authentication.
I'm trying to figure out how to make sure that User is authenticated after page reload and if not, redirect them to login page.
accessToken and refreshToken are stored in the cookies and also in Vuex
Vuex.state:
auth: {
user: {},
isAuthenticated: false,
accessToken: null,
refreshToken: null
},
Vuex.actions.refreshToken
refreshToken: async ({state, commit, dispatch}) => {
try {
await api.jwtRefresh(state.auth.refreshToken).then(response => {
if (response.status === 200) {
dispatch("setAuthData",{
accessToken:response.data.access,
isAuthenticated:true
})
}
}).catch(err => {
dispatch('logout')
});
} catch (e) {
dispatch('logout')
}
},
App.vue
export default {
data: () => ({}),
mounted() {
this.$store.dispatch('setAuthDataFromCookies')
this.$store.dispatch('refreshToken') // checks if user is authenticated, redirect to login page if not
this.$router.push('/dashboard')
}
}
My idea is to try to refresh the JWT token. If it was successfully refreshed User can proceed to /dashboard. If not, User is redirected to the /login
The problem is that mounted doesn't wait until refreshToken is done and it redirects User immediately to the /dashboard even before token is refreshed.
How can I make it wait? (The idea is that refreshToken will redirect user to /login in case of error.
You can setup a meta auth field in your router, and a global beforeEnter or beforeEach guard that checks Vuex (or your cookies, or both) for a token.
In your router.js file you'd have something like
routes: [
{
name: 'Login'
},
{
name: 'Dashboard', // + path, component, etc
meta: {
auth: true
}
}
]
Then you setup a global guard, something like this:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.auth)) {
if (!store.getters.authToken) {
next({ name: 'Login' });
} else {
next();
}
} else {
next(); // Very important to call next() in this case!
}
})
This will check before each and every route transition whether the next route has the auth meta field. If it does, it checks your Vuex state for the token, and otherwise navigates as normally.
Vue Router Docs on Navigation Guards
In your case, you're trying to authenticate the user, so you can just call your endpoint inside of the beforeEach guard and redirect like that based on the response. Just make sure to make the callback asynchronous, like router.beforeEach(async (to, from, next) => {})
I'm trying to implement RS256 JWT tokens in nestjs backend. I followed the example provided in nestjs documentation.
In my module I register the JwtModule with my private key:
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: extractKey(`${process.cwd()}/keys/jwt.private.key`),
signOptions: {
expiresIn: 3600,
},
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy, HttpStrategy],
})
export class AuthModule {}
I'm able to call auth/token endpoint and get the token but when I try to access guarded endpoint I always get 401.
Below you can find my custom JwtStrategy:
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: extractKey(`${process.cwd()}/keys/jwt.public.key`),
});
}
async validate(payload: JwtPayload) {
console.log('JwtStrategy');
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
And guarded endpoint:
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
#Get('token')
async createToken(): Promise<any> {
return await this.authService.createToken();
}
#Get('data')
#UseGuards(AuthGuard())
findAll() {
console.log('Guarded endpoint');
// This route is restricted by AuthGuard
// JWT strategy
}
}
I assume that when I call the auth/data I should see in the console at least the "JwtStrategy" string that I log in the validate method. Unfortunately it never shows up. Why the validate method is never called?
Please find the codesandbox below
You have to specify RS256 as the algorithm for in both the JwtModule and the JwtStrategy:
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: publicKey,
algorithms: ['RS256'],
^^^^^^^^^^^^^^^^^^^^^^
});
and
JwtModule.register({
secretOrPrivateKey: privateKey,
signOptions: {
expiresIn: 3600,
algorithm: 'RS256',
^^^^^^^^^^^^^^^^^^^
},
}),
Not sure if it works but you can try this
#UseGuards(AuthGuard('jwt'))
above your protected route.
It's quite possible that the public key and/or private key files were not generated in RS256 format.
I'd recommend trying the following:
https://gist.github.com/ygotthilf/baa58da5c3dd1f69fae9
Well, I'm starting with nuxt and I have following routes:
/home
/dashboard
/login
I want to protect the /dashboard, but only for users logged in with a token in Cookie.
Then i created a middleware
/middleware/auth.js
import Cookie from 'js-cookie'
export default function({ req, redirect }) {
if (process.server) {
if (!req.headers.cookie) return redirect('/login')
const jwtCookie = req.headers.cookie.split(';').find(c => c.trim().startsWith('jwt='))
if (!jwtCookie) return redirect('/login')
} else {
const jwt = Cookie.get('jwt')
if (!jwt) { window.location = '/login' }
}
}
and register the middleware in my layout or dashboard page
<script>
export default {
middleware: 'auth',
}
</script>
when I access /dashboard apparently works perfectly
but the problem is that the middleware is being registered globally, it is running on all pages, all routes
So when you access /home that is a published page, if you do not have the cookie, you end up being redirected to login page
anyone help?
How about creating a condition based on the route.path param ?
export default function({ req, redirect, route }) {
if (!route.path.includes('dashboard')) { // if path doesn't include "dashboard", stop there
return;
}
if (process.server) {
if (!req.headers.cookie) return redirect('/login')
const jwtCookie = req.headers.cookie.split(';').find(c => c.trim().startsWith('jwt='))
if (!jwtCookie) return redirect('/login')
} else {
const jwt = Cookie.get('jwt')
if (!jwt) { window.location = '/login' }
}
}
Therefore you still benefit from the pre-render middleware system.
You probably have registered your middleware/auth.js in your nuxt.config.js.
When you register a middleware in nuxt.config.js, you're registering it globally, meaning it will be called for every route change.
Docs:
https://nuxtjs.org/guide/routing#middleware
In my opinion, you should call them plugin, because of
middleware called by each route changed also you can't use middleware in layout and subComponent, you can use it as plugin and call it manually everywhere also it's reactive and runtime.
path: /plugind/auth.js
import Cookie from 'js-cookie';
export default function({ req, redirect }) {
if (process.server) {
if (!req.headers.cookie) return redirect('/login')
const jwtCookie = req.headers.cookie.split(';').find(c =>
c.trim().startsWith('jwt='))
if (!jwtCookie) return redirect('/login')
} else {
const jwt = Cookie.get('jwt')
if (!jwt) { window.location = '/login'
}
}
}
I spend the last 3 days to fix the problem , but i didnt figure out yet the issue.
Angular CLI: 6.0.8
Node: 8.11.2
OS: win32 x64
Angular: 6.0.6
multer. 1.3.1
my code at "childApi" using multer staff :
var store = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '.' + file.originalname);
}
});
var upload = multer({ storage: store , }).single('file');
router.post('/upload', function (req, res, next) {
upload(req, res, function (err) {
if (err) {
return console.log ('not working well')
}
//do all database record saving activity
return res.json({ originalname: req.file.originalname, uploadname: req.file.filename });
});
});
my code at "add-child" component using simple code :
import { Component, OnInit, Inject } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '#angular/material';
import { Child } from '../../models/child';
import { ChildService } from '../../services/child.service';
import {FileUploader } from 'ng2-file-upload';
const uri = 'http://localhost:3000/childApi/upload';
#Component({
selector: 'app-add-child',
templateUrl: './add-child.component.html',
styleUrls: ['./add-child.component.css']
})
export class AddChildComponent implements OnInit {
newChild = new Child;
uploader: FileUploader = new FileUploader({ url: uri });
attachmentList: any = [];
constructor(private childService: ChildService,
private route: ActivatedRoute,
private router: Router,
public dialogRef: MatDialogRef<AddChildComponent>,
#Inject(MAT_DIALOG_DATA) public data: any) {
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
this.attachmentList.push(JSON.parse(response));
};
}
The problem is that after I upload the file to the folder "uploads"
,I want to display my new photo on the screen.
The console give me this error :
GET unsafe:C:\fakepath\child+thinking.jpg 0 ()
If someone help its will be amazing.
Thanks...
I figure out what to do , I just put this sentences inside my code at "add-child" component using :
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
this.newChild.user_img = JSON.parse(response).uploadname;
this.attachmentList.push(JSON.parse(response));
};
}
As I understand from your post that you have doing a model named child inside your project so if you have can I take a look on it I will be grateful because I'm doing the same task except still getting the error:
Access to XMLHttpRequest at 'http://localhost:4000/file/upload' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
core.js:1449 ERROR SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at FileUploader.UploadFileComponent.uploader.onCompleteItem (upload-file.component.ts:27)
at FileUploader.push../node_modules/ng2-file-upload/file-upload/file-uploader.class.js.FileUploader._onCompleteItem (file-uploader.class.js:199)
at XMLHttpRequest.xhr.onerror [as __zone_symbol__ON_PROPERTYerror] (file-uploader.class.js:268)`
javascript html typescript angular6 multer