I am a total newbie to jwt and I thank you for your patience.
I am generating jwt in PHP with the following:
// Create token header as a JSON string
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
// Create token payload as a JSON string
$payload = json_encode(['username' => $this->username, 'password' => $this->password]);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, '<big secret>', true);
// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
All of that was just to generate the signature - $base64UrlSignature - which is then set to the key:
$this->key = $base64UrlSignature;
$token = array(
"iss" => $this->iss,
"aud" => $this->aud,
"iat" => $this->iat,
"nbf" => $this->nbf,
"data" => array(
"username" => $this->username,
"password" => $this->password
)
);
// generate jwt
$this->jwt = JWT::encode($token, $this->key);
echo json_encode(
array(
"status" => 401,
"id" => 0,
"uName" => "Guest",
"isAdmin" => "0",
"ts" => "2018-12-28 00:00:00",
"loggedIn" => false,
"msg" => "Combination of username and password not found",
"jwt" => $this->jwt
)
);
My question is, do I have to do the same on the client side in Angular, to see if it matches with the one generated by the server?
So far all that I have read, has to do with the server generating the jwt, then in Angular do the following:
localStorage.setItem("jwt", res.jwt);
Just place in local storage. Is that all there is to it?
Shouldn't there be a comparison of the token generated by the server to the token generated by the client?
If so, then how do I translate the above code to do so? For instance, what is the equivalent in Angular to Google's jwt PHP class:
$this->jwt = JWT::encode($token, $this->key);
I am adding code to the original post. The following is the interceptor that I have made:
import { ShoppingCartValuesService } from "./shopping-cart-values.service";
import { Injectable, Injector } from "@angular/core";
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest
} from "@angular/common/http";
import { Observable } from "rxjs/";
import * as jwt_decode from "jwt-decode";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(public srvc: ShoppingCartValuesService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const idToken = localStorage.getItem("jwt");
if (idToken) {
const cloned = req.clone({
headers: req.headers.set("Authorization", "Bearer " + idToken)
});
console.log("Decoded jwt token: ", this.getDecodedAccessToken(idToken));
return next.handle(cloned);
} else {
return next.handle(req);
}
}
getDecodedAccessToken(token: string): any {
try {
return jwt_decode(token);
} catch (error) {
console.log("error: ", error);
return false;
}
}
}
Which is called anytime a click is made in the links of the navbar via the click handler checkRequest() that is passed the route and later prepends the entire URL:
<li class="nav-item">
<a
class="nav-link"
data-toggle="tooltip"
title="Products"
routerLink="/products"
id="products"
(click)="checkRequest('/products')"
><span>Products</span></a
>
</li>
Modifying post once again to show console.log result from the (click)="checkRequest('/products');
CheckRequest method:
checkRequest(url) {
const newUrl = this.srvc.serverBase + url;
this.clickResponse = this.http.get(newUrl, { observe: "body" });
console.log(
"newUrl: " +
newUrl +
" this.clickResponse: " +
JSON.stringify(this.clickResponse)
);
}
From console.log when clicking the '/products' link:
newUrl: http://local.kronus:8001/products this.clickResponse: {"_isScalar":false,"source":{"_isScalar":false,"source":{"_isScalar":false,"source":{"_isScalar":true,"value":{"url":"http://local.kronus:8001/products","body":null,"reportProgress":false,"withCredentials":false,"responseType":"json","method":"GET","headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"params":{"updates":null,"cloneFrom":null,"encoder":{},"map":null},"urlWithParams":"http://local.kronus:8001/products"}},"operator":{"concurrent":1}},"operator":{}},"operator":{}}
The interceptor does not seem to be producing anything. Is there something that I missing to include the interceptor somehow?
Another update: after some more reading, I realized that I need to inject the interceptor into my login service:
private authInt: AuthInterceptor
Also, I added to the login service:
clickResponse: Observable<any>;
I moved the checkRequest method to the login service:
checkRequest(url) {
const newUrl = this.appBase + url;
return (this.clickResponse = this.http.get(newUrl, { observe: "body" }));
}
In the navbar component, I changed the method to the following calling the service's checkRequest:
checkRequest(url) {
this.srvc.checkRequest(url).subscribe(data => {
console.log("after clicking login: ", data);
});
}
Here is the 404 error in the console:
HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4200/login", ok: false, …}
error: "<!DOCTYPE html>↵<html lang="en">↵<head>↵<meta charset="utf-8">↵<title>Error</title>↵</head>↵<body>↵<pre>Cannot GET /login</pre>↵</body>↵</html>↵"
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
message: "Http failure response for http://localhost:4200/login: 404 Not Found"
name: "HttpErrorResponse"
ok: false
status: 404
statusText: "Not Found"
url: "http://localhost:4200/login"
How is it possible that /login is not found? I am literally on the login page. Is it because this checked before the app made the login page?
This is when I realized that I do not need to send '/login' but the uri to the api, which produced no errors, but no jwt in the headers either. I tried to do the same thing on admin/products page, which the following line seems to just return the payload coming from the api:
return (this.clickResponse = this.http.get(newUrl, { observe: "body" }));
Yet, I do not see anything in the headers section that jwt Authorization Bearer is passed. What am I missing?
Thanks in advance