https://github.com/felangel/fresh
🍋 A token refresh library for Dart.
https://github.com/felangel/fresh
dart dart-library dart-package dartlang dio graphql http interceptor oauth oauth2 token-refresh
Last synced: about 14 hours ago
JSON representation
🍋 A token refresh library for Dart.
- Host: GitHub
- URL: https://github.com/felangel/fresh
- Owner: felangel
- Created: 2020-04-27T04:44:10.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2025-03-02T23:07:27.000Z (12 months ago)
- Last Synced: 2025-05-15T12:02:19.015Z (10 months ago)
- Topics: dart, dart-library, dart-package, dartlang, dio, graphql, http, interceptor, oauth, oauth2, token-refresh
- Language: Dart
- Homepage: https://github.com/felangel/fresh
- Size: 459 KB
- Stars: 380
- Watchers: 8
- Forks: 58
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# Fresh 🍋
[](https://github.com/felangel/fresh/actions/workflows/main.yaml)
[](https://opensource.org/licenses/MIT)
[](https://github.com/felangel/fresh)
---
A collection of packages for automatic token refresh in Dart and Flutter. Fresh handles refreshing, caching, and attaching authentication tokens transparently so your API calls just work.
## Why Fresh?
Token-based authentication seems simple until you handle the edge cases: tokens expire mid-session, multiple requests fail at the same time triggering duplicate refreshes, refresh tokens get revoked, and you need to route users to login when auth is lost. Fresh handles all of this so you don't have to.
- No more manual 401 handling scattered across your codebase
- No more race conditions when concurrent requests trigger simultaneous refreshes
- No more stale tokens causing request failures - expired tokens are refreshed proactively before the request is even sent
## Packages
| Package | Pub |
| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [fresh](https://github.com/felangel/fresh/tree/master/packages/fresh) | [](https://pub.dev/packages/fresh) |
| [fresh_dio](https://github.com/felangel/fresh/tree/master/packages/fresh_dio) | [](https://pub.dev/packages/fresh_dio) |
| [fresh_graphql](https://github.com/felangel/fresh/tree/master/packages/fresh_graphql) | [](https://pub.dev/packages/fresh_graphql) |
| [fresh_http](https://github.com/felangel/fresh/tree/master/packages/fresh_http) | [](https://pub.dev/packages/fresh_http) |
## Features
- **Automatic token refresh** on 401 / auth errors, with automatic request retry
- **Proactive refresh** before requests when the token is expired
- **Single-flight refresh** - concurrent requests share one refresh call instead of triggering multiple
- **`authenticationStatus` stream** for reacting to login/logout events
- **Pluggable `TokenStorage`** - bring your own persistence layer
- **Built-in `OAuth2Token`** with `expiresAt` support
## Usage
### fresh_dio
```dart
final dio = Dio();
dio.interceptors.add(
Fresh.oAuth2(
tokenStorage: InMemoryTokenStorage(),
refreshToken: (token, client) async {
final response = await client.post(
'https://api.example.com/auth/refresh',
data: {'refresh_token': token?.refreshToken},
);
return OAuth2Token(
accessToken: response.data['access_token'],
refreshToken: response.data['refresh_token'],
);
},
),
);
```
See the [fresh_dio README](https://github.com/felangel/fresh/tree/master/packages/fresh_dio) for full documentation.
### fresh_graphql
```dart
import 'dart:convert';
final freshLink = FreshLink.oAuth2(
tokenStorage: InMemoryTokenStorage(),
refreshToken: (token, client) async {
final response = await client.post(
Uri.parse('https://api.example.com/auth/refresh'),
body: jsonEncode({'refresh_token': token?.refreshToken}),
);
final body = jsonDecode(response.body) as Map;
return OAuth2Token(
accessToken: body['access_token'],
refreshToken: body['refresh_token'],
);
},
shouldRefresh: (response) =>
response.errors?.any((e) => e.message.contains('UNAUTHENTICATED')) ?? false,
);
// HttpLink comes from package:gql_http_link
final link = Link.from([freshLink, HttpLink('https://api.example.com/graphql')]);
```
See the [fresh_graphql README](https://github.com/felangel/fresh/tree/master/packages/fresh_graphql) for full documentation.
### fresh_http
```dart
import 'dart:convert';
final client = Fresh.oAuth2(
tokenStorage: InMemoryTokenStorage(),
refreshToken: (token, client) async {
final response = await client.post(
Uri.parse('https://api.example.com/auth/refresh'),
body: jsonEncode({'refresh_token': token?.refreshToken}),
);
final body = jsonDecode(response.body) as Map;
return OAuth2Token(
accessToken: body['access_token'],
refreshToken: body['refresh_token'],
);
},
);
```
See the [fresh_http README](https://github.com/felangel/fresh/tree/master/packages/fresh_http) for full documentation.