Installation & Setup

Install neuctra_authix_dart_package, create one shared NeuctraAuthix instance, and teach it how to keep a session across app restarts.

1. Install

1dart pub add neuctra_authix_dart_package

The package needs Dart ^3.0.0 and pulls in a single dependency, package:http. It runs on every Dart platform: Flutter mobile, web, desktop, and plain Dart on the server or CLI.

2. Import

One import exposes the client, config, every parameter and response class, Page, SessionStore and the whole error hierarchy.

Dart
import 'package:neuctra_authix_dart_package/neuctra_authix_dart_package.dart';

3. Configure

ParamTypeRequiredDescription
appIdStringYesThe app every route is scoped to. Injected into request bodies and into app-scoped route paths.
publishableKeyString?Nopk_live_… — safe to ship in a Flutter build. Covers sign-up, sign-in, verification, password reset, and the signed-in user's own records. Supply this or secretKey, not both.
secretKeyString?Nosk_live_… — full authority over the account. Server-side only; never ship it in an app or web build.
baseUrlStringNoDefaults to https://server.authix.neuctra.com/api. A trailing slash is stripped for you.
appNameString?NoOptional display label. Cosmetic.
timeoutDurationNoPer-request timeout. Defaults to 30 seconds.
Dart
1// lib/services/authix.dart
2import 'package:neuctra_authix_dart_package/neuctra_authix_dart_package.dart';
3
4/// One shared instance for the whole app.
5final authix = NeuctraAuthix(
6  const NeuctraAuthixConfig(
7    appId: String.fromEnvironment('AUTHIX_APP_ID'),
8    publishableKey: String.fromEnvironment('AUTHIX_PUBLISHABLE_KEY'),
9    appName: 'MyApp',
10    // baseUrl defaults to the production API — override it to point at a
11    // local server during development.
12  ),
13);

Keys are checked before anything is sent

Construction throws a ConfigurationError when the key is missing, malformed, or the wrong kind — a secret key passed as publishableKey fails immediately rather than shipping account-level authority inside your app.

Dart
NeuctraAuthix(
  const NeuctraAuthixConfig(appId: appId, publishableKey: 'sk_live_…'),
);
// ConfigurationError: a secret key (sk_…) was passed as 'publishableKey'.

Upgrading from 1.x? apiKey throws with an instruction naming its replacement, rather than being silently ignored.

4. Pass credentials at build time

Dart has no .env at runtime the way a web bundler does. Use --dart-define so keys stay out of source control.

Bash
1flutter run \
2  --dart-define=AUTHIX_PUBLISHABLE_KEY=pk_live_xxxxxxxx_xxxxxxxxxxxxxxxx \
3  --dart-define=AUTHIX_APP_ID=your_app_id_here
4
5# Or keep them in a file and pass it once:
6flutter run --dart-define-from-file=authix.json

5. Constructor options

OptionTypePurpose
clienthttp.Client?Supply your own client for retries, logging, proxies, or BrowserClient on web. The SDK only closes clients it created.
sessionSessionStore?Share one cookie jar across several client instances.
timeoutDurationPer-request timeout. Defaults to 30 seconds; a timeout throws with status 0.
Dart
1final authix = NeuctraAuthix(
2  config,
3  client: myHttpClient,          // optional — bring your own http.Client
4  session: SessionStore(),       // optional — share a jar between clients
5  timeout: const Duration(seconds: 15), // optional — defaults to 30s
6);
7
8// Release the underlying client when you are done with it.
9authix.close();

6. Sessions that survive a restart

In a browser the user agent stores the HTTP-only authix_user_session cookie for you. Dart has no cookie jar, so the SDK ships SessionStore: it captures Set-Cookie from auth responses and replays it on every later call. It lives in memory, so persist it yourself.

Dart
1import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2
3const _storage = FlutterSecureStorage();
4const _key = 'authix_session';
5
6/// Call once during app start-up, before the first API call.
7Future<void> restoreSession() async {
8  final saved = await _storage.read(key: _key);
9  if (saved != null) authix.session.setSessionCookie(saved);
10}
11
12/// Call after a successful login.
13Future<void> persistSession() async {
14  final cookie = authix.session.sessionCookie;
15  if (cookie != null) await _storage.write(key: _key, value: cookie);
16}
17
18/// Call after logout.
19Future<void> forgetSession() => _storage.delete(key: _key);

Then restore it before your first API call:

Dart
1Future<void> main() async {
2  WidgetsFlutterBinding.ensureInitialized();
3
4  await restoreSession();
5
6  // checkUserSession never throws — a dead cookie simply returns false
7  // and is cleared from the store for you.
8  final session = await authix.checkUserSession();
9
10  runApp(MyApp(isLoggedIn: session.authenticated));
11}
MemberTypeUse
session.hasSessionboolIs a session cookie currently held?
session.sessionCookieString?Raw authix_user_session value — this is what you persist.
session.setSessionCookie(v)voidSeed a restored cookie on app start.
session.clearSession()voidDrop the Neuctra Authix cookie locally, forcing a signed-out state.
session.clear()voidDrop every stored cookie.

7. Flutter Web

On web the browser owns cookies and JavaScript cannot read an HTTP-only one. Hand the SDK a BrowserClient with credentials enabled and skip the persistence step entirely — the browser handles it.

Dart
1import 'package:http/browser_client.dart';
2
3// On Flutter Web the browser owns the cookie jar, so let it send
4// credentials itself. SessionStore stays empty — that is expected.
5final authix = NeuctraAuthix(
6  config,
7  client: BrowserClient()..withCredentials = true,
8);

CORS on web

Credentialed cross-origin requests require the API to send Access-Control-Allow-Credentials: true and an explicit origin — a wildcard * is rejected by the browser. Add your web origin to the app's allowed origins in the dashboard.

8. Error handling

Every failure is an AuthixException, mapped to the most specific subclass the response allows — so you can catch the case you actually handle instead of inspecting status codes by hand. Catching AuthixException still covers everything.

TypestatusWhen
ConfigurationErrorBad client setup or a missing required argument. Thrown before any request is sent.
NetworkErrorTimeout, offline, DNS or TLS failure. No response was received.
ValidationError400The API rejected the request — including a filter on a field that is not searchable.
AuthenticationError401Missing, malformed, expired or revoked credential. NoUserSessionError is the subclass for 'nobody is signed in'.
InsufficientScopeError403A publishable key on a secret-key endpoint. Carries a .hint naming the fix.
PermissionDeniedError403Authenticated but not permitted — an unverified account, or a plan limit reached.
NotFoundError404The app, user, or record does not exist under this account.
VersionConflictError409The record changed since you read it. Carries currentVersion and expectedVersion; nothing was written.
RateLimitError429Rate limited, or the monthly quota is exhausted. Carries .resetDate.
ServerError5xxThe API failed to process the request.
Dart
1try {
2  await authix.loginUser(
3    const LoginParams(email: '[email protected]', password: 'wrong'),
4  );
5} on ConfigurationError catch (err) {
6  // A required argument was empty — no request was sent.
7  print(err.message);
8} on NetworkError catch (err) {
9  // Timeout, offline, DNS or TLS failure.
10  print(err.message);
11} on AuthenticationError catch (err) {
12  // 401 — wrong password, or an expired or revoked credential.
13  print(err.message);
14} on AuthixApiError catch (err) {
15  // Anything else the API rejected.
16  print('${err.status} ${err.code}: ${err.message}');
17  print(err.payload); // the decoded response body
18}

The two you will most often handle explicitly:

Dart
1// Optimistic concurrency: pass the version you last read.
2try {
3  await authix.updateUserData(
4    UpdateUserDataParams(
5      userId: userId,
6      dataId: record.id,
7      data: {'status': 'shipped'},
8      version: record.version,
9    ),
10  );
11} on VersionConflictError catch (err) {
12  // Another device wrote first. Nothing was overwritten.
13  print('now at version ${err.currentVersion}');
14}
15
16// Wrong key for the endpoint — nearly always a pk_ key on a server-only route.
17try {
18  await authix.getAllUsersFromApp(const GetAllAppUsersParams());
19} on InsufficientScopeError catch (err) {
20  print(err.hint); // explains which credential the endpoint needs
21}

checkUserSession() never throws — any failure resolves to CheckSessionResponse(authenticated: false) and clears the stored cookie. logoutUser() clears the local session even when the server call fails, so a failed logout cannot leave a usable session on the device.

9. End-to-end flow

Dart
1// 1. Create the account — the session cookie is captured automatically
2final signup = await authix.signupUser(
3  const SignupParams(
4    name: 'John Doe',
5    email: '[email protected]',
6    password: 'secret123',
7    username: 'johndoe',
8  ),
9);
10
11final userId = signup['user']?['id']?.toString() ?? '';
12
13// 2. Verify the email address
14await authix.requestEmailVerificationOTP(
15  userId: userId,
16  email: '[email protected]',
17);
18await authix.verifyEmail(email: '[email protected]', otp: '123456');
19
20// 3. Persist the session so it survives an app restart
21await persistSession();
22
23// 4. Store something for this user
24await authix.addUserData(
25  AddUserDataParams(
26    userId: userId,
27    dataCategory: 'notes',
28    data: {'title': 'My first note'},
29  ),
30);
31
32// 5. Log out
33await authix.logoutUser(onLoggedOut: forgetSession);

Production notes

  • Never hardcode a key in source — use --dart-define.
  • Ship only pk_live_… keys. A --dart-define is compiled into the binary in plain text, so treat anything passed that way as public.
  • Persist session.sessionCookie in secure storage, not SharedPreferences.
  • Call authix.close() in short-lived Dart processes such as CLIs and tests.

You are set up

  • Auth & User Management — signup, login, sessions, profile.
  • User Data Management — per-user records and search.
  • App Data Management — shared app-level records.

Related