Unable to store the access token in angular constructor - node.js

I am able to get the access token but unable to use in a constructor method in angular service. console.log just prints the token but it is not getting assigned to a variable that I need to do.
Portion of my code.
constructor(private http: HttpClient) {
// get the access_token via Node JS
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
})
}

If you need to use the token in the constructor, make sure it is already received.
constructor(private http: HttpClient) {
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
// do your stuff
// or invoke your method
})
}
Or if you want to perform some specific stuff with the token in another method myMethod, try this
myMethod(private http: HttpClient) {
this.http.get(this.apiUrl + '/api/getToken').subscribe(d=>{
this.token = JSON.stringify(d);
console.log(this.token);
// some operation, involved with token
})
}
In this case, it is ensured that the token is retrieved and available before using it.

Related

JWT Authentication with NextJS

I've searched around a bit, but have not found any clear, up-to-date, answers on this topic.
I'm trying to implement JWT authentication in my NextJS application. The following is what I have so far.
/login endpoint that will (1) check that the user/pass exists and is valid, and (2) create a JWT token based on a private RS256 key.
Created a middleware layer to verify the JWT
The creation of the JWT is fine - it works perfectly well reading the key from the file-system and signing a JWT.
However, I've run into the problem of the middleware being unable to use node modules (fs and path) because of the edge runtime (read here). This makes it so I'm unable to read the public key from the FS.
What is the proper way to verify a JWT token on every request? I've read that fetching from middleware is bad practice and should be avoided. All other reference on this topic (that I found) either uses a "secret" instead of a key (and can therefor be put into process.env and used in middleware) or glosses over the fact (1). Or should I just create a separate express application to handle JWT creation/verifying?
What I do is add a file (_middleware.tsx) within pages. This ensures the file runs each page load but is not treated as a standard page. In this file lives an Edge function. If the user is not signed in (no JWT in cookies) and tries to access a protected page, he is immediately redirected to /signin before the server is even hit.
import { NextResponse } from "next/server";
const signedInPages = ["/admin", "/members "];
export default function middleware(req) {
if (signedInPages.find((p) => p === req.nextUrl.pathname)) {
const { MY_TOKEN: token } = req.cookies;
if (!token) {
return NextResponse.redirect("/signin");
}
}
}
If you signed the token from
import jwt from "jsonwebtoken";
then you can use same jwt for verifying token inside a middleware function. you create _middleware.js inside pages directory and middleware will run for each request before request hits the endpoint:
import { NextResponse } from "next/server";
import jwt from "jsonwebtoken";
export async function middleware(req, ev) {
const token = req ? req.cookies?.token : null;
let userId=null;
if (token) {
// this is how we sign= jwt.sign(object,secretKey)
// now use the same secretKey to decode the token
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
userId = decodedToken?.issuer;
}
const { pathname } = req.nextUrl;
// if user sends request to "/api/login", it has no token. so let the request pass
if (
pathname.includes("/api/login") || userId
) {
return NextResponse.next();
}
if (!token && pathname !== "/login") {
return NextResponse.redirect("/login");
}
}
you send the token in the post request header.
{Authorization: 'Bearer ' + token}
And then verify that token on the server, before sending data back
To verify the token you create a middleware function, then use that function on any route you want to portect
router.get("/", middlewarefunction, function (req: any, res: any, next: any) {
res.send("/api")
})

Getting the http post canceled when subscribing from a service

Stuck in this error for a week. Cannot send a simple post request to the heroku server using the Angular HttClient. Defined all the services in the provider section in the main app Module. The Error Handling service is not logging any error after sending the post request(This service works fine that i have tested in another project).
The component is defined in a different module but services are defined and provided in the root app.module.ts
These Modules that components live are imported in the main app module.
But no matter what the post request being canceled!!.
API Params
email: string
password: string
AuthModel
Model using for defining the data params for API
export interface AuthModel {
email: string;
password: string
}
AuthService.ts
This is the service i used to inject into my component.ts file for subscribing. This service also uses another service to handle the error cases HandleError
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
signUpUrl = 'myurl';
private handleError: HandleError;
constructor(private http: HttpClient, private httpErrorService: HttpErrorService) {
this.handleError = this.httpErrorService.createHandleError('AuthService'); //Problem lies here
}
signUp(authModel: AuthModel) : Observable<AuthModel>
{
return this.http.post<AuthModel>(this.signUpUrl,authModel,httpOptions).pipe( catchError(this.handleError('signup',authModel)) );
}
}
component.ts
Submit function is called when button is clicked after entering the data
Submit(): void {
this.authModel!.email = this.emailHolder.value;
this.authModel!.password = this.passwordHolder.value;
this.authService.signUp(this.authModel).subscribe((res)=> {console.log(res)});
}
The problem was with my handleError function, it get's canceled not matter the response was. So make sure guys to write a proper errorHandling function, else you will get unintended result.

Best way to store auth token in angular app [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
My angular app connects to an AdonisJS rest api thatrequires an auth token to work. This token is generated on succesful login however storing it for future requests is a problem. Ive tried to use window.sessionStorage but unfortunately this remains undefined until the user refreshes the page. Which means my angular app doesent get the token and makes the app not to work until the page is refreshed. Any suggestions or alternatives??
An example:
First, in your auth.service.ts, 2 methods to store/get the token
// STORE the token in localstore:
setToken(token:string){
// First, serialize it (but just if token is not string type).
const tokenString:string = JSON.stringify( token );
localStorage.setItem('token', tokenString);
}
// READ the token from localstorage and Deserialize
getToken(): string | null{
let token = localStorage.getItem( 'token' );
if( token !=null){
// You just need to parse if you serialized it inside setToken() method
token = JSON.parse(carItemsString);
}
return token;
}
Then, in your interceptor:
import { Injectable } from '#angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '#angular/common/http';
import { AuthService } from '../_services/auth.service';
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const url="\yourAPI\endpoint";
// Get your token
cont myToken = this.authService.getToken();
// Add authorization header with token if available
if (myToken) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentUser.user.api_token}`,
'Content-Type': 'application/json',
},
url,
});
}
...
}
More info about how to Adding and updating headers HERE
More info about how to Use the interceptor for Intercepting requests and responsesHERE
You can store your token using localStorage or sessionStorage depending on your requirements (Session storage vs localStorage on paragraph 1
If you are using Angular to make the subsequent requests, consider creating an HttpInterceptor that is responsible from reading the token from localStorage and puting it in the HTTP Header of the requests.

How to implement auto jwt token refresh before every graphql request with Apollo and React Native?

I would like to implement auto refresh jwt token before every request to GraphQL with Apollo middleware in React Native app. After every user login he gets two tokens: access and refresh. Access token it is the short one for 30-60 min for using in authorization header. And refresh token it is the long one for 60 days for confirm of refresh token graphql mutation.
My flow:
User login and gets 2 tokens -> put access token to authorization header with Appollo setContext.
User make request to GraphQL -> check expireTime of accessToken on a client side:
-> if it is not expired -> confirm request
-> if it is has expired -> call GraphQL refreshToken mutation -> get new tokens -> confirm request.
For keeping tokens on the client side i use KeyChain storage. Can you tell me please should i use Apollo cache for keeping tokens too? Should i write Apollo state for tokens? And how i can implement my flow?
GraphQL mutation
mutation UpdateTokens($refreshToken: String!, $refreshTokenId: String!)
{
updateTokens(refreshToken: $refreshToken, refreshTokenId: $refreshTokenId) {
user {
name
phone
}
accessToken
refreshToken
}
}
App.js
import React from 'react'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { ApolloProvider } from 'react-apollo'
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
import * as Keychain from 'react-native-keychain'
import AppNavigator from './AppNavigator'
const httpLink = createHttpLink({
uri: 'http://localhost:4000'
})
const cache = new InMemoryCache()
const authLink = setContext(async (req, { headers, ...context }) => {
const tokens = await Keychain.getGenericPassword()
const accessToken = tokens.username
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : ''
},
...context
}
})
const client = new ApolloClient({
link: ApolloLink.from([authLink, httpLink]),
cache,
connectToDevTools: true
})
const App = () => {
return (
<ApolloProvider client={client}>
<ApolloHooksProvider client={client}>
<AppNavigator />
</ApolloHooksProvider>
</ApolloProvider>
)
}
export default App
I honestly think you are on the right path -- as I read your required functionality I thought of apollo-link-context and was happy to see you were taking that approach. We recently had to implement similar functionality in a react-native app, which entailed attaching custom headers with authentication-related data. To retrieve this data we were required to make an async request, although ours was over the network to a third-party service. We did this all in setContext from the client just as you are. This worked well.
I do not think you need to concern yourself with updating your Apollo cache with your tokens, manually or otherwise, for at least a few reasons. First, given the quasi-sensitive nature of what you are storing, it would be best practice to defer to the more secure storage solution, which in this case is likely the Keychain. In addition, having a single source of truth for the tokens in your application can keep things clean.
Assuming you do not want to write this data to cache, I would double-check Apollo client is not automatically doing so. For example, if you for some reason previously queried your token data, Apollo might automatically update your cache upon receiving the mutation payload. Just something to be mindful of.

Problem with Authentication chapter and the 19-auth sample

I downloaded the 19-auth sample and add some console.log debug code to it, then found some problems.
The code in JwtAuthGuard is never executed: '2222222' was not printed to the console in the code below:
canActivate(context: ExecutionContext) {
console.log('22222222222');
// add your custom authentication logic here
// for example, call super.logIn(request) to establish a session.
return super.canActivate(context);
}
When I changed the guard to JwtAuthGuard in the AuthController:
#get('data')
#UseGuards(JwtAuthGuard)
findAll(#Req() req) {
return req.user;
// this route is restricted by AuthGuard
// JWT strategy
}
the code in JwtAuthGuard was invoked, but in the canActivate function, I can't get the user info from request. and the canActivate function was called before the JwtStrategy?
Can someone explain how the code executing for the auth module, and how to get the user info in the JwtAuthGuard?
paste the latest code and console log here:
JwtStrategy
/**
* jwt passport 调用validate方法来判断是否授权用户进行接口调用
* #param payload
*/
async validate(payload: AuthPayload) {
Logger.log(`payload is ${JSON.stringify(payload)}`, 'JwtStrategy');
const user = await this.authService.validateUser(payload.id);
if (!user) {
throw new UnauthorizedException('不存在的用户信息');
}
return user;
}
JwtAuthGuard
canActivate(context: ExecutionContext) {
// add your custom authentication logic here
// for example, call super.logIn(request) to establish a session.
// this.accessPriv = this.reflector.get<string>('accessPriv', context.getHandler());
console.log('canActivate executed 111111111111111111');
return super.canActivate(context);
}
and the console log as below:
canActivate executed 111111111111111111
[Nest] 14080 - 2019-04-01 11:19 [JwtStrategy] payload is {"userName":"fanliang","id":"1","iat":1553772641,"exp":1554377441} +2286ms
it seems that the canActivate() function of JwtAuthGuard executed before the validate() function of JwtStrategy, but the user info was attached to the request after JwtStrategy validate().
what I want is to get the user info from request in the canActivate() of custom AuthGuard such like JwtAuthGuard
I have a somewhat solution that works for me.
Calling the super.canActivate before my own logic.
seems like the population of req.user triggered by it.
An example:
import { ExecutionContext, Injectable } from "#nestjs/common";
import { AuthGuard } from "#nestjs/passport";
import { Request } from "express";
#Injectable()
export class AuthGuardWithAllowSentry extends AuthGuard("jwt") {
public async canActivate(context: ExecutionContext) {
// that code will call the passport jwt
const origCanActivate = await super.canActivate(context);
// now we have request.user!
const http = context.switchToHttp();
const request = http.getRequest<Request>();
console.log(request.user)
if (request.header("X-Sentry-Token") === "blablabla") {
if (request.method === "GET" && request.path.endsWith(".map")) {
return true;
}
}
// some random logic
return request.user.roles.includes("admin")
}
}
it feels for me more like a workaround than a real thing.
I agree that the 19-auth sample is a little bit confusing to follow. This is mainly because it includes the JWTAuthGuard (as a reference for building custom guards) but it is never actually used. Instead, the original use of plain AuthGuard is already set up to provide JWT functionality. However, both guards leverage the JWTStrategy. If you want to understand this better, you could try updating your AuthController:
#Get('data')
#UseGuards(AuthGuard())
findAll() {
// this route is restricted by AuthGuard
// JWT strategy
return {
message: 'Successfully passed AuthGuard',
};
}
#Get('custom-jwt')
#UseGuards(new JwtAuthGuard())
// this route is restricted by JWTAuthGuard custom
// JWT strategy
customJwt() {
return {
message: 'Successfully passed JWTAuthGuard',
};
}
The important part is that in order to get past either guard, you must send the request with the Authorization header properly set to the token that's returned from the token endpoint.
For example: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZW1haWwuY29tIiwiaWF0IjoxNTU0MDUyNDczLCJleHAiOjE1NTQwNTYwNzN9.3Q8_FC-qFXk1F4KmMrHVSmmNGPAyHdt2myr5c18_E-U
I find it easiest to use a tool like Postman or Insomnia for constructing requests and setting Headers, etc but you could also use CURL. Once you've set the Authorization header with a valid token you'll be able to hit both of the guarded endpoints. If you put a console.log in the JWTStrategy you'll see that both guards end up using the validate method to retrieve the user correctly.

Resources