diff --git a/CHANGELOG.md b/CHANGELOG.md
index d77049e..d58bde7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 2.0.0
+
+- BREAKING: `TokenStorage` now provides the option to asynchronously retrieve tokens.
+- Fix internal lint errors
+- Upgrade dependencies
+
 ## 1.0.2
 
 - Automatically refreshes expired client tokens
diff --git a/README.md b/README.md
index 931ba1c..a527f34 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Easily authenticate using OAuth 2.0 client/password grants.
 Install passputter from [pub.dev](https://pub.dev/packages/passputter):
 
 ```yaml
-passputter: ^1.0.2
+passputter: ^2.0.0
 ```
 
 ## ✅ Prerequisites
@@ -47,7 +47,7 @@ class HiveTokenStorage implements TokenStorage {
     static const _userTokenKey = 'userToken';
 
     @override
-    OAuthToken? get clientToken {
+    FutureOr<OAuthToken?> get clientToken async {
         final tokenMap = _box.get(_clientTokenKey);
         if (tokenMap != null) {
             return OAuthToken.fromJson(tokenMap);
@@ -57,7 +57,7 @@ class HiveTokenStorage implements TokenStorage {
     }
 
     @override
-    OAuthToken? get userToken {
+    FutureOr<OAuthToken?> get userToken async {
         final tokenMap = _box.get(_userTokenKey);
         if (tokenMap != null) {
             return OAuthToken.fromJson(tokenMap);
diff --git a/lib/src/client_token_interceptor.dart b/lib/src/client_token_interceptor.dart
index 4348e16..29d67a5 100644
--- a/lib/src/client_token_interceptor.dart
+++ b/lib/src/client_token_interceptor.dart
@@ -1,7 +1,6 @@
 // 📦 Package imports:
 import 'package:clock/clock.dart';
 import 'package:dio/dio.dart';
-
 // 🌎 Project imports:
 import 'package:passputter/passputter.dart';
 import 'package:passputter/src/oauth_api_interface.dart';
@@ -38,7 +37,7 @@ class ClientTokenInterceptor extends Interceptor {
     RequestOptions options,
     RequestInterceptorHandler handler,
   ) async {
-    final token = tokenStorage.clientToken;
+    final token = await tokenStorage.clientToken;
     if (token == null) {
       try {
         // No token saved; get another one.
diff --git a/lib/src/oauth_api_impl.dart b/lib/src/oauth_api_impl.dart
index 56ede8f..3adfce8 100644
--- a/lib/src/oauth_api_impl.dart
+++ b/lib/src/oauth_api_impl.dart
@@ -1,6 +1,5 @@
 // 📦 Package imports:
 import 'package:dio/dio.dart';
-
 // 🌎 Project imports:
 import 'package:passputter/src/oauth_api_interface.dart';
 import 'package:passputter/src/oauth_token.dart';
@@ -23,7 +22,7 @@ class OAuthApiImpl implements OAuthApiInterface {
     required String clientId,
     required String clientSecret,
   }) async {
-    final r = await client.post(
+    final r = await client.post<String>(
       endpoint,
       data: <String, String>{
         'client_id': clientId,
@@ -33,7 +32,7 @@ class OAuthApiImpl implements OAuthApiInterface {
       options: Options(contentType: Headers.formUrlEncodedContentType),
     );
 
-    return OAuthToken.fromJson(r.data);
+    return OAuthToken.fromJson(r.data!);
   }
 
   @override
@@ -42,7 +41,7 @@ class OAuthApiImpl implements OAuthApiInterface {
     required String clientId,
     required String clientSecret,
   }) async {
-    final r = await client.post(
+    final r = await client.post<String>(
       endpoint,
       data: <String, String>{
         'refresh_token': refreshToken,
@@ -53,7 +52,7 @@ class OAuthApiImpl implements OAuthApiInterface {
       options: Options(contentType: Headers.formUrlEncodedContentType),
     );
 
-    return OAuthToken.fromJson(r.data);
+    return OAuthToken.fromJson(r.data!);
   }
 
   @override
@@ -63,7 +62,7 @@ class OAuthApiImpl implements OAuthApiInterface {
     required String clientId,
     required String clientSecret,
   }) async {
-    final r = await client.post(
+    final r = await client.post<String>(
       endpoint,
       data: <String, String>{
         'username': username,
@@ -75,6 +74,6 @@ class OAuthApiImpl implements OAuthApiInterface {
       options: Options(contentType: Headers.formUrlEncodedContentType),
     );
 
-    return OAuthToken.fromJson(r.data);
+    return OAuthToken.fromJson(r.data!);
   }
 }
diff --git a/lib/src/oauth_token.dart b/lib/src/oauth_token.dart
index 76f10d9..e52e64d 100644
--- a/lib/src/oauth_token.dart
+++ b/lib/src/oauth_token.dart
@@ -3,8 +3,10 @@ import 'dart:convert';
 
 // 📦 Package imports:
 import 'package:clock/clock.dart';
+import 'package:meta/meta.dart';
 
 /// An authentication token.
+@immutable
 class OAuthToken {
   /// Constructs an [OAuthToken]
   const OAuthToken({
@@ -18,19 +20,19 @@ class OAuthToken {
     Map<String, dynamic> map, [
     Clock clock = const Clock(),
   ]) {
-    final expiresIn = map['expires_in'];
+    final expiresIn = map['expires_in'] as int?;
     return OAuthToken(
-      token: map['access_token'],
+      token: map['access_token'] as String,
       expiresAt: expiresIn != null
           ? clock.now().add(Duration(seconds: expiresIn))
           : null,
-      refreshToken: map['refresh_token'],
+      refreshToken: map['refresh_token'] as String?,
     );
   }
 
   /// Constructs an [OAuthToken] from a JSON [source]
   factory OAuthToken.fromJson(String source) =>
-      OAuthToken.fromMap(json.decode(source));
+      OAuthToken.fromMap(json.decode(source) as Map<String, dynamic>);
 
   /// The token used to authenticate requests.
   ///
diff --git a/lib/src/token_storage.dart b/lib/src/token_storage.dart
index 674e29a..20ecf18 100644
--- a/lib/src/token_storage.dart
+++ b/lib/src/token_storage.dart
@@ -1,13 +1,15 @@
 // 🌎 Project imports:
+import 'dart:async';
+
 import 'oauth_token.dart';
 
 /// Handles storage and retrieval of [OAuthToken]s.
 abstract class TokenStorage {
   /// Retrieves the currently saved client token if it exists, or none.
-  OAuthToken? get clientToken;
+  FutureOr<OAuthToken?> get clientToken;
 
   /// Retrieves the currently saved user token if it exists, or none.
-  OAuthToken? get userToken;
+  FutureOr<OAuthToken?> get userToken;
 
   /// Saves a new client [token].
   ///
diff --git a/lib/src/user_token_interceptor.dart b/lib/src/user_token_interceptor.dart
index e3beaf1..08a197c 100644
--- a/lib/src/user_token_interceptor.dart
+++ b/lib/src/user_token_interceptor.dart
@@ -1,7 +1,6 @@
 // 📦 Package imports:
 import 'package:clock/clock.dart';
 import 'package:dio/dio.dart';
-
 // 🌎 Project imports:
 import 'package:passputter/passputter.dart';
 import 'package:passputter/src/oauth_api_interface.dart';
@@ -38,7 +37,7 @@ class UserTokenInterceptor extends Interceptor {
     RequestOptions options,
     RequestInterceptorHandler handler,
   ) async {
-    final token = tokenStorage.userToken;
+    final token = await tokenStorage.userToken;
     if (token != null) {
       if (token.expiresAt != null && token.expiresAt!.isBefore(clock.now())) {
         final refreshToken = token.refreshToken;
@@ -62,7 +61,6 @@ class UserTokenInterceptor extends Interceptor {
           return handler.reject(
             DioError(
               requestOptions: options,
-              type: DioErrorType.other,
               error: TokenExpiredException(token),
             ),
           );
diff --git a/pubspec.yaml b/pubspec.yaml
index e527577..f0ae60d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: passputter
 description: Easily authenticate using OAuth 2.0 client/password grants.
-version: 1.0.2
+version: 2.0.0
 repository: https://github.com/netsells/passputter
 
 environment:
@@ -13,7 +13,7 @@ dependencies:
 dev_dependencies:
   import_sorter: ^4.5.0
   mock_web_server: ^5.0.0-nullsafety.1
-  mocktail: ^0.1.2
+  mocktail: ^0.2.0
   pretty_dio_logger: ^1.2.0-beta-1
   test: ^1.17.3
   time: ^2.0.0
diff --git a/test/src/oauth_api_impl_test.dart b/test/src/oauth_api_impl_test.dart
index 1793945..d3bcf82 100644
--- a/test/src/oauth_api_impl_test.dart
+++ b/test/src/oauth_api_impl_test.dart
@@ -1,11 +1,10 @@
 // 📦 Package imports:
 import 'package:dio/dio.dart';
 import 'package:mocktail/mocktail.dart';
-import 'package:test/test.dart';
-
 // 🌎 Project imports:
 import 'package:passputter/src/oauth_api_impl.dart';
 import 'package:passputter/src/oauth_token.dart';
+import 'package:test/test.dart';
 
 class MockDio extends Mock implements Dio {}
 
@@ -28,7 +27,7 @@ void main() {
   group('getClientToken', () {
     test('successfully returns token', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'client_id': clientId,
@@ -41,10 +40,12 @@ void main() {
         (_) async => Response(
           requestOptions: RequestOptions(path: endpoint),
           statusCode: 200,
-          data: '''{
+          data: '''
+          {
             "access_token": "token",
             "refresh_token": "refresh"
-          }''',
+          }
+          ''',
         ),
       );
 
@@ -64,7 +65,7 @@ void main() {
 
     test('throws DioError if one is thrown by request', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'client_id': clientId,
@@ -76,7 +77,7 @@ void main() {
       ).thenAnswer((_) => Future.error(tError));
 
       expect(
-        () async => await oAuthApi.getClientToken(
+        () async => oAuthApi.getClientToken(
           clientId: clientId,
           clientSecret: clientSecret,
         ),
@@ -90,7 +91,7 @@ void main() {
 
     test('successfully returns token', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'refresh_token': refreshToken,
@@ -104,10 +105,12 @@ void main() {
         (_) async => Response(
           requestOptions: RequestOptions(path: endpoint),
           statusCode: 200,
-          data: '''{
+          data: '''
+          {
             "access_token": "token",
             "refresh_token": "refresh"
-          }''',
+          }
+          ''',
         ),
       );
 
@@ -128,7 +131,7 @@ void main() {
 
     test('throws DioError if one is thrown by request', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'refresh_token': refreshToken,
@@ -141,7 +144,7 @@ void main() {
       ).thenAnswer((_) => Future.error(tError));
 
       expect(
-        () async => await oAuthApi.getRefreshedToken(
+        () async => oAuthApi.getRefreshedToken(
           refreshToken: refreshToken,
           clientId: clientId,
           clientSecret: clientSecret,
@@ -157,7 +160,7 @@ void main() {
 
     test('successfully returns token', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'username': username,
@@ -172,10 +175,12 @@ void main() {
         (_) async => Response(
           requestOptions: RequestOptions(path: endpoint),
           statusCode: 200,
-          data: '''{
+          data: '''
+          {
             "access_token": "token",
             "refresh_token": "refresh"
-          }''',
+          }
+          ''',
         ),
       );
 
@@ -197,7 +202,7 @@ void main() {
 
     test('throws DioError if one is thrown by request', () async {
       when(
-        () => dio.post(
+        () => dio.post<String>(
           endpoint,
           data: <String, String>{
             'username': username,
@@ -211,7 +216,7 @@ void main() {
       ).thenAnswer((_) => Future.error(tError));
 
       expect(
-        () async => await oAuthApi.getUserToken(
+        () async => oAuthApi.getUserToken(
           username: username,
           password: password,
           clientId: clientId,
diff --git a/test/src/user_token_interceptor_test.dart b/test/src/user_token_interceptor_test.dart
index 40dc172..ad9ecde 100644
--- a/test/src/user_token_interceptor_test.dart
+++ b/test/src/user_token_interceptor_test.dart
@@ -2,14 +2,13 @@
 import 'package:clock/clock.dart';
 import 'package:dio/dio.dart';
 import 'package:mocktail/mocktail.dart';
-import 'package:test/test.dart';
-import 'package:time/time.dart';
-
 // 🌎 Project imports:
 import 'package:passputter/passputter.dart';
 import 'package:passputter/src/oauth_api_interface.dart';
 import 'package:passputter/src/oauth_token.dart';
 import 'package:passputter/src/token_expired_exception.dart';
+import 'package:test/test.dart';
+import 'package:time/time.dart';
 
 class MockOAuthApi extends Mock implements OAuthApiInterface {}
 
@@ -23,7 +22,7 @@ void main() {
   late UserTokenInterceptor interceptor;
 
   setUpAll(() {
-    registerFallbackValue<DioError>(
+    registerFallbackValue(
       DioError(
         requestOptions: RequestOptions(
           path: 'path',
@@ -36,7 +35,7 @@ void main() {
     tokenStorage = InMemoryTokenStorage();
     oAuthApi = MockOAuthApi();
     handler = MockHandler();
-    clock = Clock.fixed(DateTime(2021, 1, 1));
+    clock = Clock.fixed(DateTime(2021));
     interceptor = UserTokenInterceptor(
       tokenStorage: tokenStorage,
       oAuthApi: oAuthApi,