diff --git a/.idea/angel_auth.iml b/.idea/angel_auth.iml
index 02bd9dfb..eae13016 100644
--- a/.idea/angel_auth.iml
+++ b/.idea/angel_auth.iml
@@ -5,9 +5,7 @@
-
-
diff --git a/README.md b/README.md
index f8b1b222..2a68e513 100644
--- a/README.md
+++ b/README.md
@@ -33,9 +33,15 @@ configureServer(Angel app) async {
// If the last strategy throws an authentication failure, then
// a `401 Not Authenticated` is thrown.
var chainedHandler = auth.authenticate(
- 'basic,facebook',
+ ['basic','facebook'],
authOptions
);
+
+ // Apply angel_auth-specific configuration
+ await app.configure(auth.configureServer);
+
+ // Middleware to decode JWT's...
+ app.use(auth.decodeJwt);
}
```
@@ -60,7 +66,7 @@ configureServer(Angel app) async {
// If the last strategy throws an authentication failure, then
// a `401 Not Authenticated` is thrown.
var chainedHandler = auth.authenticate(
- 'basic,facebook',
+ ['basic','facebook'],
authOptions
);
}
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 00000000..518eb901
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,2 @@
+analyzer:
+ strong-mode: true
\ No newline at end of file
diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart
index 5e4d7ae8..04460fb3 100644
--- a/lib/src/plugin.dart
+++ b/lib/src/plugin.dart
@@ -10,7 +10,7 @@ import 'options.dart';
import 'strategy.dart';
/// Handles authentication within an Angel application.
-class AngelAuth extends AngelPlugin {
+class AngelAuth {
Hmac _hs256;
num _jwtLifeSpan;
final StreamController _onLogin = new StreamController(),
@@ -27,8 +27,6 @@ class AngelAuth extends AngelPlugin {
/// The name to register [requireAuth] as. Default: `auth`.
String middlewareName;
- bool debug;
-
/// If `true` (default), then JWT's will be considered invalid if used from a different IP than the first user's it was issued to.
///
/// This is a security provision. Even if a user's JWT is stolen, a remote attacker will not be able to impersonate anyone.
@@ -69,7 +67,6 @@ class AngelAuth extends AngelPlugin {
num jwtLifeSpan,
this.allowCookie: true,
this.allowTokenInQuery: true,
- this.debug: false,
this.enforceIp: true,
this.middlewareName: 'auth',
this.reviveTokenEndpoint: "/auth/token"})
@@ -78,8 +75,7 @@ class AngelAuth extends AngelPlugin {
_jwtLifeSpan = jwtLifeSpan ?? -1;
}
- @override
- call(Angel app) async {
+ Future configureServer(Angel app) async {
if (serializer == null)
throw new StateError(
'An `AngelAuth` plug-in was called without its `serializer` being set. All authentication will fail.');
@@ -90,14 +86,13 @@ class AngelAuth extends AngelPlugin {
app.container.singleton(this);
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
- app.before.add(decodeJwt);
app.registerMiddleware(middlewareName, requireAuth);
if (reviveTokenEndpoint != null) {
app.post(reviveTokenEndpoint, reviveJwt);
}
- app.justBeforeStop.add((_) {
+ app.shutdownHooks.add((_) {
_onLogin.close();
});
}
@@ -109,56 +104,27 @@ class AngelAuth extends AngelPlugin {
}
/// A middleware that decodes a JWT from a request, and injects a corresponding user.
- decodeJwt(RequestContext req, ResponseContext res) async {
+ Future decodeJwt(RequestContext req, ResponseContext res) async {
if (req.method == "POST" && req.path == reviveTokenEndpoint) {
- // Shouldn't block invalid JWT if we are reviving it
- if (debug) print('Token revival endpoint accessed.');
return await reviveJwt(req, res);
}
- if (debug) {
- print('Enforcing JWT authentication...');
- }
-
String jwt = getJwt(req);
- if (debug) {
- print('Found JWT: $jwt');
- }
-
if (jwt != null) {
var token = new AuthToken.validate(jwt, _hs256);
- if (debug) {
- print('Decoded auth token: ${token.toJson()}');
- }
-
if (enforceIp) {
- if (debug) {
- print('Token IP: ${token.ipAddress}. Current request sent from: ${req
- .ip}');
- }
-
if (req.ip != null && req.ip != token.ipAddress)
throw new AngelHttpException.forbidden(
message: "JWT cannot be accessed from this IP address.");
}
if (token.lifeSpan > -1) {
- if (debug) {
- print("Making sure this token hasn't already expired...");
- }
-
token.issuedAt.add(new Duration(milliseconds: token.lifeSpan));
if (!token.issuedAt.isAfter(new DateTime.now()))
throw new AngelHttpException.forbidden(message: "Expired JWT.");
- } else if (debug) {
- print('This token has an infinite life span.');
- }
-
- if (debug) {
- print('Now deserializing from this userId: ${token.userId}');
}
final user = await deserializer(token.userId);
@@ -169,16 +135,8 @@ class AngelAuth extends AngelPlugin {
}
/// Retrieves a JWT from a request, if any was sent at all.
- getJwt(RequestContext req) {
- if (debug) {
- print('Attempting to parse JWT');
- }
-
+ String getJwt(RequestContext req) {
if (req.headers.value("Authorization") != null) {
- if (debug) {
- print('Found Auth header');
- }
-
final authHeader = req.headers.value("Authorization");
// Allow Basic auth to fall through
@@ -186,7 +144,6 @@ class AngelAuth extends AngelPlugin {
return authHeader.replaceAll(_rgxBearer, "").trim();
} else if (allowCookie &&
req.cookies.any((cookie) => cookie.name == "token")) {
- if (debug) print('Request has "token" cookie...');
return req.cookies.firstWhere((cookie) => cookie.name == "token").value;
} else if (allowTokenInQuery && req.query['token'] is String) {
return req.query['token'];
@@ -196,43 +153,25 @@ class AngelAuth extends AngelPlugin {
}
/// Attempts to revive an expired (or still alive) JWT.
- reviveJwt(RequestContext req, ResponseContext res) async {
+ Future