Skip to content

Instantly share code, notes, and snippets.

@jhades
Last active May 4, 2023 19:02
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save jhades/2375d4f784938d28eaa41f321f8b70fe to your computer and use it in GitHub Desktop.
Save jhades/2375d4f784938d28eaa41f321f8b70fe to your computer and use it in GitHub Desktop.
Angular Security - Authentication with JWT
{
"sub": "353454354354353453",
"exp": 1504699256
}
@Component({
selector: 'login',
template: `
<form [formGroup]="form">
<fieldset>
<legend>Login</legend>
<div class="form-field">
<label>Email:</label>
<input name="email" formControlName="email">
</div>
<div class="form-field">
<label>Password:</label>
<input name="password" formControlName="password"
type="password">
</div>
</fieldset>
<div class="form-buttons">
<button class="button button-primary"
(click)="login()">Login</button>
</div>
</form>`})
export class LoginComponent {
form:FormGroup;
constructor(private fb:FormBuilder,
private authService: AuthService,
private router: Router) {
this.form = this.fb.group({
email: ['',Validators.required],
password: ['',Validators.required]
});
}
login() {
const val = this.form.value;
if (val.email && val.password) {
this.authService.login(val.email, val.password)
.subscribe(
() => {
console.log("User is logged in");
this.router.navigateByUrl('/');
}
);
}
}
}
@Injectable()
export class AuthService {
constructor(private http: HttpClient) {
}
login(email:string, password:string ) {
return this.http.post<User>('/api/login', {email, password})
// this is just the HTTP call,
// we still need to handle the reception of the token
.shareReplay();
}
}
import {Request, Response} from "express";
import * as express from 'express';
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
import * as jwt from 'jsonwebtoken';
import * as fs from "fs";
const app: Application = express();
app.use(bodyParser.json());
app.route('/api/login')
.post(loginRoute);
const RSA_PRIVATE_KEY = fs.readFileSync('./demos/private.key');
export function loginRoute(req: Request, res: Response) {
const email = req.body.email,
password = req.body.password;
if (validateEmailAndPassword()) {
const userId = findUserIdForEmail(email);
const jwtBearerToken = jwt.sign({}, RSA_PRIVATE_KEY, {
algorithm: 'RS256',
expiresIn: 120,
subject: userId
}
// send the JWT back to the user
// TODO - multiple options available
}
else {
// send status 401 Unauthorized
res.sendStatus(401);
}
}
... continuing the implementation of the Express login route
// this is the session token we created above
const jwtBearerToken = jwt.sign(...);
// set it in an HTTP Only + Secure Cookie
res.cookie("SESSIONID", jwtBearerToken, {httpOnly:true, secure:true});
... continuing the implementation of the Express login route
// this is the session token we created above
const jwtBearerToken = jwt.sign(...);
// set it in the HTTP Response body
res.status(200).json({
idToken: jwtBearerToken,
expiresIn: ...
});
import * as moment from "moment";
@Injectable()
export class AuthService {
constructor(private http: HttpClient) {
}
login(email:string, password:string ) {
return this.http.post<User>('/api/login', {email, password})
.do(res => this.setSession)
.shareReplay();
}
private setSession(authResult) {
const expiresAt = moment().add(authResult.expiresIn,'second');
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()) );
}
logout() {
localStorage.removeItem("id_token");
localStorage.removeItem("expires_at");
}
public isLoggedIn() {
return moment().isBefore(this.getExpiration());
}
isLoggedOut() {
return !this.isLoggedIn();
}
getExpiration() {
const expiration = localStorage.getItem("expires_at");
const expiresAt = JSON.parse(expiration);
return moment(expiresAt);
}
}
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>,
next: HttpHandler): Observable<HttpEvent<any>> {
const idToken = localStorage.getItem("id_token");
if (idToken) {
const cloned = req.clone({
headers: req.headers.set("Authorization",
"Bearer " + idToken)
});
return next.handle(cloned);
}
else {
return next.handle(req);
}
}
}
import * as express from 'express';
const app: Application = express();
//... define checkIfAuthenticated middleware
// check if user authenticated only in certain routes
app.route('/api/lessons')
.get(checkIfAuthenticated, readAllLessons);
const expressJwt = require('express-jwt');
const RSA_PUBLIC_KEY = fs.readFileSync('./demos/public.key');
const checkIfAuthenticated = expressJwt({
secret: RSA_PUBLIC_KEY
});
app.route('/api/lessons')
.get(checkIfAuthenticated, readAllLessons);
{
"keys": [
{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"x5c": [
"MIIDJTCCAg2gAwIBAgIJUP6A\/iwWqvedMA0GCSqGSIb3DQEBCwUAMDAxLjAsBgNVBAMTJWFuZ3VsYXJ1bml2LXNlY3VyaXR5LWNvdXJzZS5hdXRoMC5jb20wHhcNMTcwODI1MTMxNjUzWhcNMzEwNTA0MTMxNjUzWjAwMS4wLAYDVQQDEyVhbmd1bGFydW5pdi1zZWN1cml0eS1jb3Vyc2UuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUvZ+4dkT2nTfCDIwyH9K0tH4qYMGcW\/KDYeh+TjBdASUS9cd741C0XMvmVSYGRP0BOLeXeaQaSdKBi8uRWFbfdjwGuB3awvGmybJZ028OF6XsnKH9eh\/TQ\/8M\/aJ\/Ft3gBHJmSZCuJ0I3JYSBEUrpCkWjkS5LtyxeCPA+usFAfixPnU5L5lyacj3t+dwdFHdkbXKUPxdVwwkEwfhlW4GJ79hsGaGIxMq6PjJ\/\/TKkGadZxBo8FObdKuy7XrrOvug4FAKe+3H4Y5ZDoZZm5X7D0ec4USjewH1PMDR0N+KUJQMRjVul9EKg3ygyYDPOWVGNh6VC01lZL2Qq244HdxRwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH\/MB0GA1UdDgQWBBRwgr0c0DYG5+GlZmPRFkg3+xMWizAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBACBV4AyYA3bTiYWZvLtYpJuikwArPFD0J5wtAh1zxIVl+XQlR+S3dfcBn+90J8A677lSu0t7Q7qsZdcsrj28BKh5QF1dAUQgZiGfV3Dfe4\/P5wUaaUo5Y1wKgFiusqg\/mQ+kM3D8XL\/Wlpt3p804dbFnmnGRKAJnijsvM56YFSTVO0JhrKv7XeueyX9LpifAVUJh9zFsiYMSYCgBe3NIhIfi4RkpzEwvFIBwtDe2k9gwIrPFJpovZte5uvi1BQAAoVxMuv7yfMmH6D5DVrAkMBsTKXU1z3WdIKbrieiwSDIWg88RD5flreeTDaCzrlgfXyNybi4UTUshbeo6SdkRiGs="
],
"n": "wUvZ-4dkT2nTfCDIwyH9K0tH4qYMGcW_KDYeh-TjBdASUS9cd741C0XMvmVSYGRP0BOLeXeaQaSdKBi8uRWFbfdjwGuB3awvGmybJZ028OF6XsnKH9eh_TQ_8M_aJ_Ft3gBHJmSZCuJ0I3JYSBEUrpCkWjkS5LtyxeCPA-usFAfixPnU5L5lyacj3t-dwdFHdkbXKUPxdVwwkEwfhlW4GJ79hsGaGIxMq6PjJ__TKkGadZxBo8FObdKuy7XrrOvug4FAKe-3H4Y5ZDoZZm5X7D0ec4USjewH1PMDR0N-KUJQMRjVul9EKg3ygyYDPOWVGNh6VC01lZL2Qq244HdxRw",
"e": "AQAB",
"kid": "QzY0NjREMjkyQTI4RTU2RkE4MUJBRDExNzY1MUY1N0I4QjFCODlBOQ",
"x5t": "QzY0NjREMjkyQTI4RTU2RkE4MUJBRDExNzY1MUY1N0I4QjFCODlBOQ"
}
]
}
const jwksRsa = require('jwks-rsa');
const expressJwt = require('express-jwt');
const checkIfAuthenticated = expressJwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksUri: "https://angularuniv-security-course.auth0.com/.well-known/jwks.json"
}),
algorithms: ['RS256']
});
app.route('/api/lessons')
.get(checkIfAuthenticated, readAllLessons);
@petitgougou
Copy link

Hello,

Where is the code and documentation for the following functions:

  1. validateEmailAndPassword
    2.findUserIdForEmail
    3.readAllLessons

Thanks for your help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment