Provides integrations and configuration for implementing authentication within your Dart applications and servers. Supports multiple OAuth2/OpenIdConnect providers and custom credentials such as email, phone, username or time-based one-time password (TOTP).
Flutter package for an integrated authentication flow and a package:shelf
web server for implementing the backend authentication endpoints.
This repository is a monorepo with the following packages:
Package | Description | pub.dev |
---|---|---|
dart_auth | Core package with all models and the logic for implementing the server or client applications |
|
dart_auth_shelf | Shelf bindings for implementing authentication for a backend web server using shelf |
|
dart_auth_flutter | Widgets and API integration for authentication in Flutter applications |
- Dart Authenticator
- Table Of Contents
- Features
- Endpoints
- Access Tokens and Authentication Headers
- Providers
- Persistence and Models
- OAuth2 Authentication Flows
- Admin Dashboard
- Backend Config
- Frontend Client
- Translations, Localization and Internationalization (l10n and i18n)
TODO: Put a short description of the package here that helps potential users know whether this package might be useful for them.
HTTP Method | Path | Path Params | Input Payload | Output Body | Description |
---|---|---|---|---|---|
GET | oauth/providers | ||||
GET | oauth/url/$providerId | - $providerId: String | |||
GET | oauth/device/$providerId | - $providerId: String | |||
GET/POST | oauth/callback/$providerId | - $providerId: String | |||
GET | oauth/state | ||||
WS | oauth/subscribe | ||||
POST | jwt/refresh | ||||
POST | jwt/revoke | ||||
GET | user/me | ||||
POST | user/mfa | ||||
DELETE | providers/delete/$providerId | - $providerId: String | |||
PUT | credentials/update/$providerId | - $providerId: String | |||
POST | credentials/signin/$providerId | - $providerId: String | |||
POST | credentials/signup/$providerId | - $providerId: String | |||
GET | admin/users |
GET "/providers"
Returns a list of the supported authentication providers. Separated between OAuth and Credentials providers. Useful for presenting the sign up and sign in forms.
POST "/credentials/signin"
Logs in an user using a credentials providers
// TODO: ask for user if they would like to create an account
POST "/credentials/signup"
Registers an user using a credentials providers
POST "/jwt/revoke"
Logs out an user. The access tokens are not revoked, only the refresh token is revoked. The session is updated so the endedAt
date is set to the current timestamp and a session ended event is saved.
// TODO: Not implemented. Manage multiple sessions
// TODO: Encryption
POST "/jwt/refresh"
Retrieves a new access token from a refresh token. Return Unauthorized if the refresh token has been revoked.
GET or POST "oauth/callback/"
The OAuth2 authentication providers will send a request to this endpoint with the result of the authentication flow.
We use JSON Web Tokens (JWT) for managing user authentication and a session for revoking access. The token should be sent through the Authorization
HTTP header.
We use the package:jose
A session contains the information about the authentication state and other metadata such as the device, platform, last login date the authentication providers used.
We implement multiple predefined authentication providers for social sign in though OAuth2 and OpenID Connect.
You may add additional scopes, for example for the GoogleProvider
, you may add a scope to access the user's Google Drive and backup you application data, the TwitterProvider
to write tweets, the DiscordProvider
to send messages or the GithubProvider
to access private repositories.
provider | logo | scope | documentation | implicit flow | device flow | phone | picture | OpenId | |
---|---|---|---|---|---|---|---|---|---|
Apple | "openid name email" | OpenIdConnect, Revoke, Apps | ❌ | ❌ | ✅* | ❌ | ❌ | config | |
Discord | "identify email" | OAuth2, Apps, User, Scopes | ✅ | ❌ | ✅ | ❌ | ✅* | ❌ | |
"public_profile,email" | OAuth2, Device, Revoke, User, Scopes | ❌ | ✅ | ✅ | ❌ | ✅ | ✅* | ||
Github | "read:user user:email" | OAuth2, Device, Revoke, User, Scopes | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | |
"openid email profile" | OAuth2, OpenIDConnect, Scopes Device | ❌ | ✅ | ✅ | ❌ | ✅ | config | ||
Microsoft | "openid email profile offline_access" | OpenIDConnect, Apps, User | ✅ | ✅ | ✅ | ❌ | ✅ | config | |
"identity" | OAuth2, ClientCredentials, Apps, User | ✅ | ❌ | ❌* | ❌ | ❌* | ❌ | ||
Spotify | "user-read-private user-read-email" | OAuth2, Revoke, User | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | |
Twitch | "user:read:email openid" | Scopes | ✅ | ❌ | ✅ | ❌ | ✅ | config | |
"users.read tweet.read offline.access" | OAuth2, Revoke, User, UserModel, TokenModel | ❌ | ❌ | ✅* | ❌ | ✅ | ❌ |
GitLab TikTok Dropbox Atlassian Slack
// TODO:
We use Argon2 though the package:argon2
for hashing the passwords. The passwordHash
is stored in the account Model with the Argon2 configuration used to create it.
You may use isolates for hashing. This allows to share the compute load between isolates.
Passwordless login is also implemented for email and phone providers through magic links or authentication codes sent to the email or phone. The provider gives you the authentication code, you may choose to only presente it as a link or show the code to the user. You can configure the way the code is generated.
You have to use an external provider for sending the verification email or sms. For email you may use a services such as Mailjet and send the email using package:mailer
, or perhaps by using an API given by the email or sms provider (some expose REST APIs, for example).
Multi-Factor authentication allows you to increase the security of your users' accounts by adding other authentication steps before an user can be signed in. For that, we provide the following configuration:
- Required providers: The set of required providers to sign in.
- Optional providers: The set of optional providers to sign in.
- Optional amount: The number of optional providers to satisfy in order to sign in into the account.
You may combine any OAuth2 or Credential provider in your configuration.
If you have the following configuration:
- Required providers: [
provider1
] - Optional providers: [
provider2
,provider3
] - Optional amount: 1
You will need to sign in with provider1
since it is required as well as at least one (the optional amount) of provider2
or provider3
.
We use the package:otp
for computing the TOTP from the shared secret.
This allows the user to sign in with an authenticator application that supports Time-Base One-Time Passwords (TOTP) such as Google Authenticator, Twilio Authy or Microsoft Authenticator.
When using the backend server, the information should be stored to maintain the user's authentication providers, the user's account, sessions and other authentication information.
You may use any database or service for storing the information by implementing the Persistence Interface
. We provide a InMemoryPersistence
for testing and an SQLPersistence
for SQL databases.
The tables used by the authentication server are the following:
The main user table saves the user's id
, name
, picture
, the creation date and the multi factor authentication configuration as a JSON String (multiFactorAuth
). The userId is the primary key and it is immutable along with the createdAt
.
CREATE TABLE IF NOT EXISTS ${tables.user} (
userId TEXT NOT NULL,
name TEXT NULL,
picture TEXT NULL,
createdAt DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
multiFactorAuth $jsonType NOT NULL,
PRIMARY KEY (userId)
);
Each user can have multiple authentication provider accounts. They save the information required to access the user's data rawUserData
and expose typical user information such as the email
, phone
, name
and picture
retrieved from the authentication provider.
CREATE TABLE IF NOT EXISTS ${tables.account} (
userId TEXT NOT NULL,
providerId TEXT NOT NULL,
providerUserId TEXT NOT NULL,
name TEXT NULL,
picture TEXT NULL,
email TEXT NULL,
emailIsVerified BOOL NOT NULL,
phone TEXT NULL,
phoneIsVerified BOOL NOT NULL,
rawUserData $jsonType NOT NULL,
createdAt DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (providerId, providerUserId),
FOREIGN KEY (userId) REFERENCES ${tables.user} (userId)
);
An user can have multiple sessions. This is used to revoke sessions, when the endedAt
Date is not null, then the session has ended and the refreshToken
can not be used to retrieve a new access token. mfa
contains the authentication providers used to authenticate the session. meta
is other custom user or session information and deviceId
maybe set to identify sessions within a given device.
CREATE TABLE IF NOT EXISTS ${tables.session} (
sessionId TEXT NOT NULL,
deviceId TEXT NULL,
refreshToken TEXT NULL,
userId TEXT NOT NULL,
meta $jsonType NULL,
mfa $jsonType NOT NULL,
endedAt DATE NULL,
createdAt DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (sessionId),
FOREIGN KEY (userId) REFERENCES ${tables.user} (userId)
);
The authentication state is a simple key-value table with information of authentication flows. They save the status and other metadata of authentication requests that require user interaction and may unfinished. For example, OAuth2 flows or Email/Phone magic links/codes that require the user to authorize the app or input an authorization code. This is also used for Multi-Factor Authentication flows.
CREATE TABLE IF NOT EXISTS ${tables.authState} (
key TEXT NOT NULL,
value $jsonType NOT NULL,
createdAt DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (key)
);
A table with the events that occur to an user's account. Useful for tracing the account's behavior and identifying unwanted access.
CREATE TABLE IF NOT EXISTS ${tables.userEvent} (
key TEXT NOT NULL,
type TEXT NOT NULL,
value $jsonType NOT NULL,
sessionId TEXT NOT NULL,
userId TEXT NOT NULL,
createdAt DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (userId) REFERENCES ${tables.user} (userId)
FOREIGN KEY (sessionId, userId) REFERENCES ${tables.session} (sessionId, userId)
PRIMARY KEY (createdAt, key),
UNIQUE (key)
);
At the moment, the following event types are recorder:
- MFA Updated
- Authentication Provider Created
- Authentication Provider Updated
- Authentication Provider Deleted
- Authentication Provider Revoked
- Session Created
- Session Updated
- Session Revoked
This provides external APIs access to validate an user's account or accessing and editing their information. In this way you can implement social sign in.
The main way to access external APIs to validate the account of an user or accessing or editing their information (though scopes).
Should only be used if you are certain the device cannot open a browser or have limited input capabilities. You should probably use Authentication Code flow for CLI apps since you may print the url for the user to open the browser on their device. This may be a problem for Smart TVs however.
Some providers requiere additional configuration (Facebook's CLIENT_TOKEN) or limit the scopes that can be requested (Google device flow allowed scopes).
Not all providers support this flow.
In general, you should not use this unless the app is frontend only or the access is one-time only (or you don't care that the user gives permissions every time).
Not all providers support this flow.
Dashboard for managing user accounts.
late final Map<String, AuthenticationProvider> allProviders; final List translations; final Persistence persistence; final String baseRedirectUri; final JsonWebTokenMaker jwtMaker;
// TODO: maybe get it from the database?
You may provide multiple RateLimit
s for a given endpoint, which allows you to configure a different amount of requests allowed for different time window sizes. For example, a rate of 100 requests in 1 minute and a 500 requests in an hour allows for bursts of 100 petitions in a single minute, but the can't surpass 500 requests in an hour.
We provide a RateLimiter implementation PersistenceRateLimiter
that provides an eventually-consistent sliding window algorithm. It tracks the sliding counters in memory and relies on transactions in the persistence store to periodically sync the local count data with the shared persistence.
When the count reaches the configured rate limit,
Name | Type | Description | Example |
---|---|---|---|
RateLimit-Policy | String | The configuration of the policy | 10;w=60;comment="sliding window"' |
RateLimit-Limit | amount | The amount of requests available in the time window | 10 |
RateLimit-Remaining | amount | The amount of additional requests that can be performed given the current count |
1 |
RateLimit-Reset | seconds | The number of seconds from now where the count will reset. Since this is a sliding window algorithm, will be the resolution, otherwise it will be the amount of seconds the client needs to wait. |
15 |
Retry-After | seconds | Same as RateLimit-Reset | 15 |
You may configure the maximum amount of time that a request can be performed since the session was created.
We provide a client facing API for the front end.
Contains translations and global state and settings for the client such as the selected theme brightness and locale.
Main authentication logic of the client.
State for the Admin Dashboard section of the application.
You may also use the Flutter library with pre-made widgets that allow the user to:
- Sign up/in/out
- View their information such as account events and sessions
- Change the multi-factor authentication
- View, add, update and delete their authentication providers
- Manage multiple accounts per device
At the moment we provide the following translations:
- English
- Spanish
However, other translations may be added in the server or client configuration.
Contains the messages sent to the client
This class provides a way to represent a message that can be translated using a Backend Translations
class.
For the frontend we also provide a way to change the texts shown to the user. You may implement the FrontEndTranslations
interface.
TODO: List prerequisites and provide or point to information on how to start using the package.
TODO: Include short and useful examples for package users. Add longer examples
to /example
folder.
const like = 'sample';
TODO: Tell users more about the package: where to find more information, how to contribute to the package, how to file issues, what response they can expect from the package authors, and more.