Search code examples
dartauthorizationaqueduct

Dart Aqueduct server basic authorization


I'm learning about how authentication works using the Aqueduct framework.

In my channel.dart file I have a route:

router
  .route('/protected') 
  .link(() => Authorizer.basic(validator))
  .link(() => ProtectedController()); 

But I don't know how to create the validator. In the docs I see that I can make a custom Authorizer without using an AuthServer. The code example is this:

class BasicValidator implements AuthValidator {
  @override
  FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {}
    var user = await userForName(usernameAndPassword.username);
    if (user.password == hash(usernameAndPassword.password, user.salt)) {
      return Authorization(...);
    }

    return null;
  }
}

I'd like to make a basic working example, but this is the closest that I could get:

class BasicValidator implements AuthValidator {
  @override
  FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {

    final validUsername = 'bob';
    final validPassword = 'password123';

    // How do I get the parsed username?
    // How do I get the parsed password?

    if (parsedUsername == validUsername && parsedPassword == validPassword) {
      // How do I create an Authorization?
      return Authorization(...);
    }

    return null;
  }

  // What is this?
  @override
  List<APISecurityRequirement> documentRequirementsForAuthorizer(APIDocumentContext context, Authorizer authorizer, {List<AuthScope> scopes}) {
    return null;
  }
}

Could anyone show me a basic working example of Basic authorization validator?


Solution

  • authorizationData is an instance of AuthBasicCredentials when using Authorizer.basic. An object of this type has username and password fields derived from parsing the 'Authorization' header from a request.

    An Authorization object is a container for data related to the authorized resource owner (such as their user ID). It is used by subsequent controllers to control authorization without having to look up the authorized user again; you should populate it with any authorization information you have available.

    documentRequirementsForAuthorizer is used during OpenAPI document generation. An Authorizer that uses your validator will encode the returned security requirements into the OpenAPI operations being secured.

    See also http://aqueduct.io/docs/auth/authorizer/#using-authorizers-without-authserver.

    @override
    FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {
    
        final validUsername = 'bob';
        final validPassword = 'password123';
    
        final credentials = authorizationData as AuthBasicCredentials;
    
        if (credentials.username == validUsername 
        && credentials.password == validPassword) {
    
          return Authorization(
           null, // no client ID for basic auth 
           await getUserIDFromUsername(validUsername), // This is your problem to solve
           this, // always this
           credentials: credentials // if you want to pass this info along 
           );
        }
    
        return null;
      }