Coffee & Code - Nakama Sessions & Authentication

Coffee & Code - Nakama Sessions & Authentication

Master Nakama's session system for secure user authentication in game backends with practical Flutter examples.


Sample Image
Cappuccino from Café Zeppelin in Laureles, Medellín, Colombia.

In one of my most recent applications, known as Gift Grab, the concept of a user's "session" was implemented in a rather simplistic way.

Sample Image
Nakama Website

It was solely based on whether the user had signed into the app or not.

Sample Image
Nakama Sessions

Unfortunately, this approach did not take into account the exact moment of sign-in or the duration of the user's interaction with the app.

Sample Image
Flutter UI with Sessions

However, as I delved deeper into the comprehensive and detailed documentation provided by Nakama, a realization dawned on me.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nakama/nakama.dart';
import 'package:nakama_ui/data/services/hive_session_service.dart';

/// Provider used to check if the user is authenticated.
class NakamaAuthProvider extends AsyncNotifier<bool> {
  /// HiveSessionService instance.
  final _hiveSessionService = HiveSessionService();

  @override
  FutureOr<bool> build() async {
    // Initialize Nakama client.
    getNakamaClient(
      host: '127.0.0.1',
      ssl: false,
      serverKey: 'defaultkey',
      httpPort: 7350,
    );

    // Fetch the current session.
    final session = await _hiveSessionService.sessionActive();

    return session != null;
  }
}

It became clear that I should be leveraging the concept of sessions to manage user interactions with the app in a much more effective and efficient way.

Sample Image
Nakama Leaderboards

To provide a bit of context, broadly speaking, a "session" refers to a distinct period during which a user is authenticated with a particular system.

Sample Image

It represents an established connection between the user and the system, facilitating a secure and personalized interaction.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nakama/nakama.dart';
import 'package:nakama_ui/data/services/hive_session_service.dart';

/// Provider that handles listing/creating leaderboard records.
class NakamaLeaderboardProvider extends AsyncNotifier<List<LeaderboardRecord>> {
  /// Leaderboard name.
  static const _leaderboardName = 'weekly_leaderboard';

  /// HiveSessionService instance.
  final _hiveSessionService = HiveSessionService();

  @override
  FutureOr<List<LeaderboardRecord>> build() async {
    // Fetch the current session.
    final session = await _hiveSessionService.sessionActive();

    // If session is null, return empty list.
    if (session == null) {
      return [];
    }

    // Get leaderboard records.
    final leaderboardRecordList =
        await getNakamaClient().listLeaderboardRecords(
      session: session,
      leaderboardName: _leaderboardName,
    );

    // Return leaderboard records from list.
    return leaderboardRecordList.records;
  }
}

In the context of Nakama, the session takes on an even more critical role. It is represented as a client-side object that authenticates the client when they are accessing server functions.

Sample Image

This implementation provides a significantly more secure way for users to interact with server functions, thereby improving overall app security.

// Decode the session token.
final res = JwtDecoder.decode(session.token);

// Return session data from decoded token.
return SessionData(
  uid: res['uid'],
  username: res['usn'],
  email: res['vrs']['email'],
  expiresAt: DateTime.fromMillisecondsSinceEpoch(res['exp'] * 1000),
);

There is more to come on this topic, so stay tuned for more insights and revelations in the near future.