Aqueduct Authorization and Authentication Snippets

Enable OAuth 2.0

import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct/managed_auth.dart';

class AppSink extends RequestSink {
  AppSink(ApplicationConfiguration appConfig) : super(appConfig) {
    var dataModel = new ManagedDataModel.fromCurrentMirrorSystem();
    var psc = new PostgreSQLPersistentStore.fromConnectionInfo(
        "username",
        "password",
        "localhost",
        5432
        "my_app");

    ManagedContext.defaultContext = new ManagedContext(dataModel, psc);

    var authStorage = new ManagedAuthStorage<User>(ManagedContext.defaultContext);
    authServer = new AuthServer(authStorage);
  }

  AuthServer authServer;

  @override
  void setupRouter(Router router) {
    router.route("/auth/token").generate(() => new AuthController(authServer));  
  }
}

Add OAuth 2.0 Clients to Database

aqueduct auth add-client \
  --id com.app.test \
  --secret supersecret \
  --allowed-scopes 'profile kiosk:location raw_db_access.readonly' \
  --connect postgres://username:[email protected]:5432/my_app

Require OAuth 2.0 Scope to Access Routes

import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct/managed_auth.dart';

class AppSink extends RequestSink {
  AppSink(ApplicationConfiguration appConfig) : super(appConfig) {
    var dataModel = new ManagedDataModel.fromCurrentMirrorSystem();
    var psc = new PostgreSQLPersistentStore.fromConnectionInfo(
        "username",
        "password",
        "localhost",
        5432
        "my_app");

    ManagedContext.defaultContext = new ManagedContext(dataModel, psc);

    var authStorage = new ManagedAuthStorage<User>(ManagedContext.defaultContext);
    authServer = new AuthServer(authStorage);
  }

  AuthServer authServer;

  @override
  void setupRouter(Router router) {
    router.route("/auth/token").generate(() => new AuthController(authServer));

    router
      .route("/profile")
      .pipe(new Authorizer.bearer(authServer, scopes: ["profile.readonly"]))
      .generate(() => new ProfileController());
  }
}

class ProfileController extends HTTPController {
  @httpGet
  Future<Response> getProfile() async {
    var id = request.authorization.resourceOwnerIdentifier;
    return new Response.ok(await profileForUserID(id));
  }
}

Basic Authentication

import 'package:aqueduct/aqueduct.dart';

class AppSink extends RequestSink {
  AppSink(ApplicationConfiguration appConfig) : super(appConfig) {
    passwordVerifier = new PasswordVerifier();
  }

  PasswordVerified passwordVerifier;

  @override
  void setupRouter(Router router) {
    router
      .route("/profile")
      .pipe(new Authorizer.basic(passwordVerifier))
      .listen((req) async => new Response.ok(null));
  }
}

class PasswordVerifier extends AuthValidator {
  @override
  Future<Authorization> fromBasicCredentials(AuthBasicCredentials usernameAndPassword) async {
    if (!isPasswordCorrect(usernameAndPassword)) {
      return null;
    }

    return new Authorization(null, usernameAndPassword.username, this);
  }

  @override
  Future<Authorization> fromBearerToken(String bearerToken, {List<AuthScope> scopesRequired}) {
    throw new HTTPResponseException(400, "Use basic authorization");
  }
}

Add OAuth 2.0 Authorization Code Flow

import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct/managed_auth.dart';

class AppSink extends RequestSink {
  AppSink(ApplicationConfiguration appConfig) : super(appConfig) {
    var dataModel = new ManagedDataModel.fromCurrentMirrorSystem();
    var psc = new PostgreSQLPersistentStore.fromConnectionInfo(
        "username",
        "password",
        "localhost",
        5432
        "my_app");

    ManagedContext.defaultContext = new ManagedContext(dataModel, psc);

    var authStorage = new ManagedAuthStorage<User>(ManagedContext.defaultContext);
    authServer = new AuthServer(authStorage);
  }

  AuthServer authServer;

  @override
  void setupRouter(Router router) {
    router.route("/auth/token").generate(() => new AuthController(authServer));  

    router.route("/auth/code").generate(() => new AuthCodeController(authServer,
        renderAuthorizationPageHTML: renderLoginPage));
  }

  Future<String> renderLoginPage(
    AuthCodeController controller, Uri requestURI, Map<String, String> queryParameters) async {

    return """
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>

<body>
<div class="container">
    <h1>Login</h1>
    <form action="${requestURI.path}" method="POST">
        <input type="hidden" name="state" value="${queryParameters["state"]}">
        <input type="hidden" name="client_id" value="${queryParameters["client_id"]}">
        <input type="hidden" name="response_type" value="code">
        <div class="form-group">
            <label for="username">User Name</label>
            <input type="text" class="form-control" name="username" placeholder="Please enter your user name">
        </div>
        <div class="form-group">
            <label for="password">Password</label>
            <input type="password" class="form-control" name="password" placeholder="Please enter your password">
        </div>
        <button type="submit" class="btn btn-success">Login</button>
    </form>
</div>
</body>

</html>
    """;    
  }
}