> ## Documentation Index
> Fetch the complete documentation index at: https://docs.golansertifikasi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Login dan panggil endpoint terproteksi dari aplikasi web atau Android.

## Siapkan base URL

Untuk stack lokal gunakan `http://localhost:18080/api/v1` di web dan `http://10.0.2.2:18080/api/v1` di Android Emulator. `10.0.2.2` adalah alias emulator ke loopback komputer development ([dokumentasi Android](https://developer.android.com/studio/run/emulator-networking-address)). Di production, gunakan `https://<domain-api-anda>/api/v1`; domain tersebut perlu ditentukan dan dikonfigurasi sebelum playground dapat mengirim request langsung.

## Login dengan Google

Klien mendapatkan `id_token` dari alur Google Sign-In lalu menukarkannya ke backend. Jangan kirim Google client secret atau kredensial server ke aplikasi.

```bash theme={null}
export API_BASE_URL="http://localhost:18080/api/v1"

curl -X POST "$API_BASE_URL/auth/google" \
  -H 'Content-Type: application/json' \
  -d '{"id_token":"<GOOGLE_ID_TOKEN>"}'
```

Respons sukses berisi `access_token`, `token_type`, `expires_in`, `onboarding_required`, dan `user`. Access token berlaku 15 menit.

## Panggil profil

```bash theme={null}
curl "$API_BASE_URL/me" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

## Contoh JavaScript

```javascript theme={null}
const apiBaseUrl = "http://localhost:18080/api/v1";

async function getProfile(accessToken) {
  const response = await fetch(`${apiBaseUrl}/me`, {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const body = await response.json();
  if (!response.ok) throw new Error(`${response.status}: ${body.code}`);
  return body;
}
```

## Contoh Dart/Flutter

```dart theme={null}
final apiBaseUrl = 'http://10.0.2.2:18080/api/v1';

final loginResponse = await http.post(
  Uri.parse('$apiBaseUrl/auth/google'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({'id_token': googleIdToken}),
);
if (loginResponse.statusCode < 200 || loginResponse.statusCode >= 300) {
  throw Exception('Login failed: ${loginResponse.statusCode}');
}
final loginBody = jsonDecode(loginResponse.body) as Map<String, dynamic>;
final accessToken = loginBody['access_token'] as String;

final response = await http.get(
  Uri.parse('$apiBaseUrl/me'),
  headers: {'Authorization': 'Bearer $accessToken'},
);
if (response.statusCode < 200 || response.statusCode >= 300) {
  throw Exception('API request failed: ${response.statusCode}');
}
final profile = jsonDecode(response.body) as Map<String, dynamic>;
```

Tambahkan `package:http/http.dart` dan `dart:convert` untuk contoh tersebut. Perangkat fisik membutuhkan alamat host yang dapat dijangkau; port local Compose saat ini hanya bind ke loopback. Minta token Google melalui SDK Google Sign-In yang sesuai dengan platform; jangan menanam kredensial backend di aplikasi.

## Jalankan backend lokal

Gunakan base URL lokal setelah stack Compose aktif. Untuk alur login yang berfungsi, konfigurasi Google Client ID dan kunci signing pada backend.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.