diff --git a/pom.xml b/pom.xml
index 0eb1b58..1104515 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,6 +62,12 @@
5.8.1
test
+
+ com.auth0
+ java-jwt
+ 3.18.2
+ true
+
diff --git a/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java
new file mode 100644
index 0000000..f8bd09c
--- /dev/null
+++ b/src/main/java/org/javawebstack/webutils/security/AbstractAuthSystem.java
@@ -0,0 +1,90 @@
+package org.javawebstack.webutils.security;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import org.javawebstack.abstractdata.AbstractObject;
+import org.javawebstack.httpserver.Exchange;
+
+import java.sql.Date;
+import java.time.Instant;
+import java.util.Optional;
+
+public abstract class AbstractAuthSystem {
+ private Algorithm algorithm;
+ private int tokenExpire = 3600;
+
+ public AbstractAuthSystem(String secret) {
+ this(Algorithm.HMAC256(secret));
+ }
+
+ public AbstractAuthSystem(Algorithm algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ protected abstract Optional getUserByUsername(String username);
+ protected AbstractObject successMessage(String token) {
+ return new AbstractObject()
+ .set("success", true)
+ .set("token", token);
+ }
+
+ public void setTokenExpire(int tokenExpire) {
+ this.tokenExpire = tokenExpire;
+ }
+
+ public int getTokenExpire() {
+ return tokenExpire;
+ }
+
+ public AbstractObject loginHandler(Exchange exchange) {
+ AbstractObject body = exchange.body(AbstractObject.class);
+ Optional oUser = getUserByUsername(body.string("username"));
+ if (!oUser.isPresent())
+ throw new AuthException("Wrong credentials");
+ IUser user = oUser.get();
+ if (!user.checkPassword(body.string("password")))
+ throw new AuthException("Wrong credentials");
+ return successMessage(signToken(user));
+ }
+
+ public boolean tokenHandler (Exchange exchange) {
+ String bearer = exchange.bearerAuth();
+ if (bearer != null) {
+ DecodedJWT jwt = JWT.require(algorithm).acceptExpiresAt(System.currentTimeMillis()).build().verify(bearer);
+ if (jwt != null)
+ exchange.attrib("jwt", jwt);
+ }
+ return false;
+ }
+
+ public Object authMiddleware (Exchange exchange) {
+ if (exchange.attrib("jwt") == null) {
+ exchange.status(401);
+ throw new AuthException("Authentication required");
+ }
+ return null;
+ }
+
+ public IUser currentUser () {
+ Exchange exchange = Exchange.current();
+ if (exchange == null)
+ throw new RuntimeException("Exchange not available in current Thread!");
+ IUser user = exchange.attrib("user");
+ if (user == null) {
+ DecodedJWT jwt = exchange.attrib("jwt");
+ if (jwt == null)
+ throw new RuntimeException("JWT not found! Is the tokenHandler in place?");
+ user = getUserByUsername(jwt.getSubject()).get();
+ exchange.attrib("user", user);
+ }
+ return user;
+ }
+
+ protected String signToken(IUser user) {
+ return JWT.create()
+ .withSubject(user.getUsername())
+ .withExpiresAt(Date.from(Instant.now().plusSeconds(tokenExpire)))
+ .sign(algorithm);
+ }
+}
diff --git a/src/main/java/org/javawebstack/webutils/security/AuthException.java b/src/main/java/org/javawebstack/webutils/security/AuthException.java
new file mode 100644
index 0000000..6758b09
--- /dev/null
+++ b/src/main/java/org/javawebstack/webutils/security/AuthException.java
@@ -0,0 +1,7 @@
+package org.javawebstack.webutils.security;
+
+public class AuthException extends RuntimeException {
+ public AuthException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/org/javawebstack/webutils/security/IUser.java b/src/main/java/org/javawebstack/webutils/security/IUser.java
new file mode 100644
index 0000000..1452393
--- /dev/null
+++ b/src/main/java/org/javawebstack/webutils/security/IUser.java
@@ -0,0 +1,14 @@
+package org.javawebstack.webutils.security;
+
+import org.javawebstack.httpserver.Exchange;
+import org.javawebstack.webutils.crypt.BCrypt;
+
+public interface IUser {
+ String getUsername();
+
+ String getPassword();
+
+ default boolean checkPassword (String password) {
+ return BCrypt.check(getPassword(), password);
+ }
+}
diff --git a/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java b/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java
new file mode 100644
index 0000000..44f1650
--- /dev/null
+++ b/src/main/java/org/javawebstack/webutils/security/SimpleAuthSystem.java
@@ -0,0 +1,22 @@
+package org.javawebstack.webutils.security;
+
+import org.javawebstack.orm.ORM;
+import org.javawebstack.orm.exception.ORMConfigurationException;
+import org.javawebstack.orm.wrapper.SQL;
+
+import java.util.Optional;
+
+public class SimpleAuthSystem extends AbstractAuthSystem {
+ public SimpleAuthSystem(String secret, SQL sql) {
+ super(secret);
+ try {
+ ORM.register(SimpleUser.class, sql);
+ } catch (ORMConfigurationException e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected Optional getUserByUsername(String username) {
+ return Optional.ofNullable(ORM.repo(SimpleUser.class).where("username", username).first());
+ }
+}
diff --git a/src/main/java/org/javawebstack/webutils/security/SimpleUser.java b/src/main/java/org/javawebstack/webutils/security/SimpleUser.java
new file mode 100644
index 0000000..70f9f6b
--- /dev/null
+++ b/src/main/java/org/javawebstack/webutils/security/SimpleUser.java
@@ -0,0 +1,51 @@
+package org.javawebstack.webutils.security;
+
+import com.auth0.jwt.algorithms.Algorithm;
+import org.javawebstack.orm.Model;
+import org.javawebstack.orm.annotation.Column;
+import org.javawebstack.orm.util.KeyType;
+
+
+public class SimpleUser extends Model implements IUser {
+
+ @Column(id = true, ai = true, key = KeyType.PRIMARY)
+ private long id;
+ @Column
+ private String username;
+ @Column
+ private String password;
+
+ public SimpleUser() {}
+
+ public SimpleUser(long id, String username, String password) {
+ this.id = id;
+ this.username = username;
+ this.password = password;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}