What is JWT

  • JSON Web Token (JWT)
    • popular way to authenticate users in a web application. It is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS).
    • Compact, url safe means of representing claims to securely transmit information between parties.
      • These claims are encoded as JSON objects that are digitally signed using a JSON web signature
    • Concise and efficient representation, allows for ease of transmissions over networks
    • No need to reference external source/database to validate info
  • Common use cases:
    • Authentication
    • information exchange
    • Authorization
    • Secure your APIs!

Popcorn hack: list 3 real world applications of JWT:

  • User Authentication: JWT (JSON Web Tokens) is commonly used for securely transmitting user authentication information between a client and a server.
  • Single Sign-On (SSO): JWT enables Single Sign-On, allowing users to authenticate once and gain access to multiple applications.
  • Information Exchange: JWT is used for the safe and efficient exchange of information between parties, ensuring data integrity and optional encryption.

Why do you need JWT

JSON Web Tokens (JWT) are crucial for secure and efficient user authentication in web development.

  • They help manage user identity and sessions across different parts of a system.
  • They play a key role in stateless authentication, allowing servers to verify user identity without storing session data.
  • JWTs are especially useful in decentralized systems, enabling smooth communication between different services and ensuring secure user roles and permissions.
  • JWTs simplify and enhance user authentication in modern web development.

Components of JWT

  • What is a web token?
    • A web token is a piece of information that represents a user’s identity or session and is used for authentication and authorization in web applications. It is typically a string of characters, often encoded in a JSON format, and is digitally signed to ensure its integrity.
  • This is the structure of a JSON Web Token:
  1. Header
    • The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm that is used, such as HMAC SHA256 or RSA SHA256. It is Base64Url encoded to form the first part of the JWT
  2. Payload
    • Claims and user data
    • claims are statements about the entity (users)
    • There are three types of claims:
      • registered: predefined claims that are no mandatory but recommended
      • public: claims defined within the IA and JSON web token registry
      • private: custom claims created to share information between parties that agree to using them
  3. Signature
    • Ensuring integrity and authenticity
    • verify the sender of the JWT
    • function
      • Creating a signature
      • Verification process
      • Signature tampering activity

Deep Dive into Anatomy of JWT

  • Navigate to this website: Link

Encoded: Json Web Token (what you send to and from the client) Decoded: algorithm, data, verify token hasn’t been changed

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

// header
{
    "alg": "HS256", //type of sign in algorithm used for encoding and decoding
    "typ": "JWT"    //type of token
}
  • Base 64 encoded
  • useful to signature type to decode
// payload
{
"sub": "123", //example of a registered claim
"name": "jwt lesson",
"iat": 1516239022",
"authorities": [
    "ADMIN",
    "MANAGER"
],
"extra-claims": "some data here"
}

  • where all different data for applciation is
  • sub = subject : id of user you’re authenticating
  • iat = issued at (when token was created)
  • exp/eat = expired at (date when toke becomes invalid)
//signature
{
HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    your-256-bit-secret
) secret base64 encoded
}
  • verify user does not change with token before it is sent back to you
  • input your secret key
  • uses algorithm in header to encode data (header + payload) using specific secret key
  • if header/payload is changed, signature will not match

Header

import java.util.Base64;

public class JwtHeaderExample {
    public static void main(String[] args) {
        // JWT Header
        String algorithm = "HS256";
        String type = "JWT";

        // Combine Header properties
        String header = "{\"alg\":\"" + algorithm + "\",\"typ\":\"" + type + "\"}";

        // Base64 URL encode the header
        String base64UrlHeader = Base64.getUrlEncoder().encodeToString(header.getBytes());

        System.out.println("JWT Header: " + base64UrlHeader);
    }
}

// Run this code
JwtHeaderExample.main(null);

Payload

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class JwtPayloadExample {
    public static void main(String[] args) {
        // JWT Payload (Claims)
        Map<String, Object> claims = new HashMap<>();
        claims.put("name", "Grace");
        claims.put("class", "CSA");
        claims.put("exp", System.currentTimeMillis() + 1800000); // 30 minutes expiration

        // Convert Claims to JSON and Base64 URL encode the payload
        String payload = mapToJson(claims);
        String base64UrlPayload = Base64.getUrlEncoder().encodeToString(payload.getBytes());

        System.out.println("JWT Payload: " + base64UrlPayload);
    }

    private static String mapToJson(Map<String, Object> map) {
        // Implement JSON conversion logic (use your preferred approach)
        return "{ \"customKey\": \"customValue\" }";
    }
}

// Run This Code
JwtPayloadExample.main(null);

Signature

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class JwtSignatureExample {
    public static void main(String[] args) {
        // Secret key for encoding and decoding
        String secretKey = "your secret key";

        // Combine Header and Payload with a period '.'
        String base64UrlHeader = "base64UrlHeader"; // Placeholder for the actual base64UrlHeader
        String base64UrlPayload = "base64UrlPayload"; // Placeholder for the actual base64UrlPayload
        String headerPayload = base64UrlHeader + "." + base64UrlPayload;

        // Generate HMAC SHA-256 signature
        byte[] signature = HmacSha256(headerPayload, secretKey);

        // Base64 URL encode the signature
        String base64UrlSignature = Base64.getUrlEncoder().encodeToString(signature);

        System.out.println("JWT Signature: " + base64UrlSignature);
    }

    private static byte[] HmacSha256(String data, String key) {
        try {
            Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretKey);
            return sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Error while generating HMAC SHA-256", e);
        }
    }
}

// Run
JwtSignatureExample.main(null);

Putting It Together

Popcorn hack: write some comments that identify each part of the JWT

  • header
  • payload
  • signature
  • algorithm
  • secret key

etc

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class JwtGenerator {

    public static void main(String[] args) {
        String secretKey = "yourSecretKey"; // secret key used for signing the JWT
        String subject = "userId123"; // subject, typically user ID or username
        long expirationTimeMillis = System.currentTimeMillis() + 3600000; // JWT expiration time

        String jwt = buildJwt(secretKey, subject, expirationTimeMillis);

        System.out.println("Generated JWT: " + jwt);
    }

    private static String buildJwt(String secretKey, String subject, long expirationTimeMillis) {
        String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; // header with algorithm & token type
        String payload = "{\"sub\":\"" + subject + "\",\"iat\":" + System.currentTimeMillis() / 1000 +
                ",\"exp\":" + expirationTimeMillis / 1000 + "}"; // payload with subject, issued at, and expiration time

        String encodedHeader = base64UrlEncode(header); // encoded header
        String encodedPayload = base64UrlEncode(payload); // encoded payload

        String dataToSign = encodedHeader + "." + encodedPayload; // data to be signed (header.payload)
        String signature = signData(dataToSign, secretKey); // signature

        return dataToSign + "." + signature; // final JWT (header.payload.signature)
    }

    private static String base64UrlEncode(String input) {
        return Base64.getUrlEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8)); // Base64 URL encoding
    }

    private static String signData(String data, String secretKey) {
        try {
            Mac sha256Hmac = Mac.getInstance("HmacSHA256"); // specifying the HMAC SHA256 algorithm
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretKeySpec); // initializing the Mac with the secret key
            byte[] signature = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)); // generating the signature
            return base64UrlEncode(new String(signature, StandardCharsets.UTF_8)); // encoding the signature
        } catch (Exception e) {
            throw new RuntimeException("Error signing JWT", e); // error handling
        }
    }
}

JwtGenerator.main(null);

Generated JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQxMjMiLCJpYXQiOjE3MDMwMDE3OTIsImV4cCI6MTcwMzAwNTM5Mn0=.24Tvv71877-9AQjvv71I77-977-977-977-9WO-_ve-_ve-_ve-_vQXvv73vv71bGe-_ve-_ve-_vSHbue-_vQ==

JWT with Spring Boot

Big Idea

JWTProcess

  1. JwtAuthFilter is executed first (validates and checks JWT Tokens)
    • Internal check to check if the token is there or not.
    • Extracts the subject (username or email)
    • If token is missing → 403 error sent
    • If token is there:
      • Makes a call using the UserDetails Service to fetch user info from the database. Uses the subject extracted to do so
      • Response comes back from the database (user either exists or doesn’t)
      • If the user does not exist → 403 error sent
      • If user exists → validate JWT process is started
  2. Validate JWT Process
    • Calls the jwt service which takes the user and jwt token as parameters
    • Token isn’t valid → 403 error sent
    • Token is valid → update the security context holder and set the connected user. User is now authenticated yay!
    • Automatically dispatch request → sent to dispatcher servlet → sent to controller → allow all execution user wants to do
    • Sends http 200

Here is a diagram that makes it easier to understand the process tha happens between JWT and the API calls. JWTApi

  • User posts with their login information
  • server does authentication to confirm the user
  • store the user in the memory of the server, send a corresponding ID with a cookie back to the client
  • Now every time the user sends a request, the cookie with that corresponding ID gets send to the server which verifies the ID and sends back a response.

Popcorn Hack: Screenshot 2024-01-08 at 9 26 50 AM

JWT Walkthrough

  • Clone this repo and follow along in each JWT file: https://github.com/vivianknee/jwtlessonBackend.git

Logic flow

Step 1 (Client - Login Request): The client sends a login request with user credentials (username and password) to the /authenticate endpoint.

Step 2 (JwtApiController):

  • The JwtApiController receives the login request.
  • It authenticates the user credentials using the AuthenticationManager.
  • If authentication is successful: Retrieves user details using the PersonDetailsService. Generates a JWT using the JwtTokenUtil. Sends the JWT as an HTTP-only secure cookie in the response.

Step 3 (Client - Subsequent Requests):

  • The client includes the JWT cookie in the headers of subsequent requests.

Step 4 (JwtRequestFilter):

  • For each incoming request, the JwtRequestFilter intercepts the request.
  • Extracts the JWT from the HTTP request headers or cookies.
  • Validates the JWT using the JwtTokenUtil.
  • If the token is valid, sets up authentication using Spring Security’s SecurityContextHolder.

Step 5 (Spring Security):

  • Spring Security processes the request with the authenticated user.
  • The application can now authorize the user based on the roles and permissions associated with the JWT.

Step 6 (Error Handling - JwtAuthenticationEntryPoint):

  • If the JWT is missing, invalid, or expired, and the request requires authentication, the JwtAuthenticationEntryPoint handles the authentication failure.
  • Responds with an HTTP 401 (Unauthorized) status.

Storing JWT

There are a few different options for storing a JWT in a JavaScript application:

  1. Cookies: You can store the JWT in a cookie and send it back to the server with each request. This is a simple and widely-supported option, but it has some limitations. For example, you can’t access cookies from JavaScript on a different domain, and some users may have cookies disabled in their browser settings.

  2. Local storage: You can store the JWT in the browser’s local storage (localStorage) or session storage (sessionStorage). This option allows you to access the JWT from JavaScript on the same domain, but it is vulnerable to cross-site scripting (XSS) attacks, where an attacker can inject malicious code into your application and steal the JWT from the storage.

  3. HttpOnly cookie: You can store the JWT in an HttpOnly cookie, which is a cookie that can only be accessed by the server and not by client-side JavaScript. This option provides some protection against XSS attacks, but it is still vulnerable to other types of attacks, such as cross-site request forgery (CSRF).

Postman

  1. Trying to access /api/person/ without jwt token stored in Cookies
    • nojwt
  2. Trying to access /api/person/ with a wrong jwt token stored in Cookies
    • wrongjwt
  3. Trying to access /api/person/ with a jwt token that does not have the signature
    • nosignature
  4. Accessing /api/person/ with generated jwt token stored in Cookies header
    • yes

Implementation Approaches and Security Considerations

JWTs are signed to ensure they cannot be modified in transit. Signature is a crucial aspect of JWT security.

Key Usage

  • Token Issuance: When the token is issued by the authorization server, it is signed with a key.
  • Token Reception: When the client receives the token, the signature is validated using the key.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Claims;

public class TokenReceptionExample {

    // Simulate receiving a token from the client
    private static String receiveTokenFromClient() {
        // In a real scenario, this would be received from the client (e.g., from a request header)
        return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiAiMTIzIiwgImV4cCI6IDE2MjM5NzYzODF9.4X1lC5fU4dV1n9l02LZyGQSy5K-O5fnZM0t6eO-w2Qs";
    }

    public static void main(String[] args) {
        // Example of Token Reception
        String receivedToken = receiveTokenFromClient();
        System.out.println("Received Token: " + receivedToken);
    }
}

Symmetric vs. Asymmetric Key Approaches

  • Symmetric Key: A single secret key is used both to sign and validate the token.
  • Asymmetric Key: Different keys are used to sign and validate the token, only the authorization server has the ability to sign it.
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.Keys;

import java.security.Key;

public class SymmetricKeyValidationExample {

    // Symmetric Key for Token Signing and Validation
    private static Key symmetricKey = Keys.secretKeyFor(io.jsonwebtoken.SignatureAlgorithm.HS256);

    // Token Validation with Symmetric Key
    private static Claims validateTokenSymmetric(String token) {
        try {
            // Parse and verify the token using the symmetric key and the HS256 algorithm
            Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(symmetricKey).build().parseClaimsJws(token);
            return claimsJws.getBody();
        } catch (ExpiredJwtException e) {
            // Handle case where the token has expired
            System.out.println("Token has expired");
        } catch (MalformedJwtException e) {
            // Handle case where the token is invalid (e.g., tampered with)
            System.out.println("Invalid token");
        }
        return null;
    }

    public static void main(String[] args) {
        // Example of Token Validation with Symmetric Key
        String receivedToken = receiveTokenFromClient();
        Claims validatedClaims = validateTokenSymmetric(receivedToken);
        if (validatedClaims != null) {
            System.out.println("Validated Payload: " + validatedClaims);
        }
    }
}

Additional Security Considerations

  • Token Scope: limit token access to specific resources or actions
  • Token Revocation: implement mechanism to revoke token if user’s access needs to be taken away
  • Token Encryption: encrypt token if it contains sensitive information that shouldn’t be visible (even if intercepted)
  • Regular Key Rotation: rotate keys regularly for security and to limit the impact of compromised key

Hacks

  1. Implementation
    • Implement a simple authentication system using JWT with Java. Show how JWT works with postman. Get the request to be authorized
  2. MC Knowledge test (5)
    • Which part of the JWT contains the actual data (claims)?
      • Header
      • Payload
      • Signature
      • Encryption
    • What is the purpose of the header in a JWT?
      • It contains the signature for the JWT.
      • It identifies the algorithm used to generate the signature.
      • It holds the encrypted data.
      • It contains the user’s information.
    • How are the parts of a JWT (header, payload, and signature) separated?
      • Comma
      • Period
      • Colon
      • Semicolon
    • Which algorithm is commonly used for JWT signatures?
      • HMAC (Hash-based Message Authentication Code)
      • RSA (Rivest-Shamir-Adleman)
      • AES (Advanced Encryption Standard)
      • MD5 (Message Digest Algorithm 5)
    • How are JWTs commonly transmitted?
      • Only via HTTP headers
      • Only as query parameters in the URL
      • In the request body as JSON
      • Any of the above, depending on the application
  3. Which part of the JWT contains the actual data (claims)?
    • Header
    • Payload
    • Signature
    • Encryption
  4. What is the purpose of the header in a JWT?
    • It contains the signature for the JWT.
    • It identifies the algorithm used to generate the signature.
    • It holds the encrypted data.
    • It contains the user’s information.
  5. How are the parts of a JWT (header, payload, and signature) separated?
    • Comma
    • Period
    • Colon
    • Semicolon
  6. Which algorithm is commonly used for JWT signatures?
    • HMAC (Hash-based Message Authentication Code)
    • RSA (Rivest-Shamir-Adleman)
    • AES (Advanced Encryption Standard)
    • MD5 (Message Digest Algorithm 5)
    • Note: Both HMAC and RSA are commonly used, depending on whether a shared secret (HMAC) or a public/private key pair (RSA) is used.
  7. How are JWTs commonly transmitted?
    • Only via HTTP headers
    • Only as query parameters in the URL
    • In the request body as JSON
    • Any of the above, depending on the application
import java.util.Base64;

public class Base64SecretDecoder {
    public static void main(String[] args) {
        String encoded = "bmlnaHRoYXdrY29kaW5nc29jaWV0eWFwY29tcHV0ZXJzY2llbmNlYQ==";
        byte[] decodedArray = Base64.getDecoder().decode(encoded);
        String decodedString = new String(decodedArray);
        System.out.println("Decoded Text: " + decodedString);
    }
}
Base64SecretDecoder.main(null);

Decoded Text: nighthawkcodingsocietyapcomputersciencea
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class TokenDecoder {
    public static void main(String[] args) {
        String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0b2J5QGdtYWlsLmNvbSIsImlhdCI6MTcwMzA5OTc5MSwiZXhwIjoxNzAzMTE3NzkxfQ.UQw28DUtxf3ketLOFij8PgzP5KCnSdUpvV8W4ZDiMqE";
        String[] parts = jwt.split("\\.");
        String header = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8);
        String payload = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
        System.out.println("Header: " + header);
        System.out.println("Payload: " + payload);
    }
}
TokenDecoder.main(null)
Header: {"alg":"HS256"}
Payload: {"sub":"toby@gmail.com","iat":1703099791,"exp":1703117791}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class SignatureGenerator {
    public static void main(String[] args) {
        String secret = "nighthawkcodingsocietyapcomputersciencea";
        String header = "base64UrlHeader"; 
        String payload = "base64UrlPayload"; 
        String toSign = header + "." + payload;
        byte[] signatureBytes = createHmacSha256Signature(toSign, secret);
        String signature = Base64.getUrlEncoder().encodeToString(signatureBytes);
        System.out.println("Signature: " + signature);
    }

    private static byte[] createHmacSha256Signature(String data, String key) {
        try {
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            hmac.init(secretKeySpec);
            return hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Error in HMAC SHA-256 generation", e);
        }
    }
}
SignatureGenerator.main(null)
Signature: jbCRgHmCs98Ah8n3CWn92WyXU3-RtdDRo9gO5pmm39o=

Screenshot 2024-01-09 at 9 44 07 AM

For extra, I have the jwt coded in python I did previously

from flask import Flask, render_template, url_for, redirect, Blueprint, request, jsonify, make_response, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, login_user, LoginManager, login_required, logout_user, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import InputRequired, Length, ValidationError
from flask_bcrypt import Bcrypt
from flask_restful import Api, Resource
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
from functools import wraps

import http.cookies as cookies
from __init__ import app, db, bcrypt

#Creates a flask application instance and assigns it to the variable flask
# Sets configuration for SQLAlchemy specifying database URI 
# hashed-passwords

login_manager = LoginManager()
# This line creates an instance of the LoginManager class from the flask_login library
login_manager.init_app(app)
# This line initializes the LoginManager instance with your Flask application, app. 
# This is required in order to use the functionality provided by flask_login.


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
# The load_user function takes a single argument user_id which is the user's identifier.
# The function returns a user object obtained by querying the User model for the user with the specified user_id. 
# The user object is then stored in the current session,  allowing the application to keep track of the user's identity and state between requests.

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), nullable=False, unique=True)
    password = db.Column(db.String(80), nullable=False)


        
#used to store user information in the database


# This function is to Verify if token is valid, Signature portion of the token
def token_required(f):
   @wraps(f)
   def decorator(*args, **kwargs):
       token = None
       # Grabs the cookie from request  headers
       cookieString = request.headers.get('Cookie')
       # loads the cookie into cookie object
       if cookieString:
           cookie = cookies.SimpleCookie()
           cookie.load(cookieString)
            # if token exist then it grabs the token from the cookie
           if 'token' in cookie:
               token = cookie['token'].value
 
        # if no token exits it shows a message saying valid token is missing 
       if not token:
           return jsonify({'message': 'a valid token is missing'})
        # this code tries to verify the signature of the token by decoding it.
       try:
           data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
           current_user = User.query.filter_by(username=data['name']).first()
        # if signature is not valid or it is not able to decode it writes a message saying token is invalid. 
       except:
           return jsonify({'message': 'token is invalid'})
        # returns current user
       return f(current_user, *args, **kwargs)
       # returns the decorator
   return decorator


# This code is actually a special function. This function will create a custom decorator with the code required to create and validate tokens. Python provides a very amazing feature named function decorators. These function decorators allow very neat features for web development. In Flask, each view is considered as a function, and decorators are used for injecting additional functionality to one or more functions. In this case, the functionality handled by this custom decorator will be to create and validate tokens.



class RegisterForm(FlaskForm):
    username = StringField(validators=[
                           InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})

    password = PasswordField(validators=[
                             InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})

    show_password = BooleanField('Show Password')

    submit = SubmitField('Register')


    def validate_username(self, username):
        existing_user_username = User.query.filter_by(
            username=username.data).first()
        if existing_user_username:
            raise ValidationError(
                'The username already exists. Please choose a different username.')
#This checks if there is already a username in the database and if there is it asks the user to choose a different username

class LoginForm(FlaskForm):
    username = StringField(validators=[
                           InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})

    password = PasswordField(validators=[
                             InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})

    submit = SubmitField('Login')











if __name__ == "__main__":
    app.run(debug=True)
# Enables flask debug mode




import threading

# import "packages" from flask
from flask import render_template  # import render_template from "public" flask libraries

# import "packages" from "this" project
from __init__ import app, db  # Definitions initialization
from model.jokes import initJokes
from model.Inspos import initInspos
from model.ISPEs import initISPEs
from model.Inputworkouts import initInputworkouts
from model.workouts import initworkouts

# setup APIs
from api.covid import covid_api # Blueprint import api definition
from api.joke import joke_api # Blueprint import api definition
from api.Inspo import Inspo_api
from api.ISPE import ISPE_api
from api.Inputworkout import Inputworkout_api
from api.workout import workout_api
from api.jwt_routes import jwt_api

# setup App pages
from projects.projects import app_projects # Blueprint directory import projects definition

# register URIs
app.register_blueprint(joke_api) # register api routes
app.register_blueprint(covid_api) # register api routes
app.register_blueprint(Inspo_api) # register api routes
app.register_blueprint(app_projects) # register app pages
app.register_blueprint(ISPE_api) # register api routes
app.register_blueprint(Inputworkout_api) # register api routes
app.register_blueprint(workout_api)
app.register_blueprint(jwt_api)


@app.errorhandler(404)  # catch for URL not found
def page_not_found(e):
    # note that we set the 404 status explicitly
    return render_template('404.html'), 404

@app.route('/')  # connects default URL to index() function
def index():
    return render_template("index.html")

@app.route('/stub/')  # connects /stub/ URL to stub() function
def stub():
    return render_template("stub.html")



@app.before_first_request
def activate_job():
    db.init_app(app)
    initJokes()
    initInspos()
    initISPEs()
    initInputworkouts()
    initworkouts()
    initapp1()


#@app.after_request
#def after_request(response):
    #response.headers.add('Access-Control-Allow-Origin', '*')
    #response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization')
    #response.headers.add('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS, PATCH')
    #return response

if __name__ == "__main__":
    # change name for testing
    from flask_cors import CORS
    cors = CORS(app)
    app.run(debug=True, host="0.0.0.0", port="8081")