Practise login screens, token storage and authenticated requests with demo accounts.
Every app needs a login screen, and testing it usually means waiting for a backend. The Fake Auth API answers like a real one: send a username and password, receive an access token and a refresh token (signed JWTs), then send Authorization: Bearer <token> to get the current user.
Wrong passwords return 401, expired or edited tokens are rejected, and you can choose a short lifetime to test your refresh logic. Demo only: the signing key is public, so never use these tokens to protect real data.
const res = await fetch('https://toolorca.com/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"username": "sokha.chan",
"password": "demo1234",
"expiresInMins": 60
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.post(
Uri.parse('https://toolorca.com/api/v1/auth/login'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'username': 'sokha.chan',
'password': 'demo1234',
'expiresInMins': 60,
}),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val json = """
{
"username": "sokha.chan",
"password": "demo1234",
"expiresInMins": 60
}
""".trimIndent()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/auth/login")
.post(json.toRequestBody("application/json".toMediaType()))
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
const token = 'YOUR_ACCESS_TOKEN';
const res = await fetch('https://toolorca.com/api/v1/auth/me', {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
const token = 'YOUR_ACCESS_TOKEN';
final res = await http.get(
Uri.parse('https://toolorca.com/api/v1/auth/me'),
headers: {'Authorization': 'Bearer $token'},
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val token = "YOUR_ACCESS_TOKEN"
val client = OkHttpClient()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/auth/me")
.header("Authorization", "Bearer $token")
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
import Foundation
let token = "YOUR_ACCESS_TOKEN"
var request = URLRequest(url: URL(string: "https://toolorca.com/api/v1/auth/me")!)
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode < 400 else {
throw URLError(.badServerResponse)
}
print(String(decoding: data, as: UTF8.self))
const res = await fetch('https://toolorca.com/api/v1/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"refreshToken": "YOUR_REFRESH_TOKEN",
"expiresInMins": 60
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final res = await http.post(
Uri.parse('https://toolorca.com/api/v1/auth/refresh'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'refreshToken': 'YOUR_REFRESH_TOKEN',
'expiresInMins': 60,
}),
);
if (res.statusCode >= 400) throw Exception('HTTP ${res.statusCode}');
final data = jsonDecode(utf8.decode(res.bodyBytes));
print(data);
}
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
// Call from a background thread or coroutine (Dispatchers.IO), never the main thread.
val client = OkHttpClient()
val json = """
{
"refreshToken": "YOUR_REFRESH_TOKEN",
"expiresInMins": 60
}
""".trimIndent()
val request = Request.Builder()
.url("https://toolorca.com/api/v1/auth/refresh")
.post(json.toRequestBody("application/json".toMediaType()))
.build()
client.newCall(request).execute().use { res ->
if (!res.isSuccessful) error("HTTP ${res.code}")
println(res.body?.string())
}
All 30 fake users can log in with the password demo1234. Good ones to start with: sokha.chan (admin), dara.sok (moderator), sophea.kim (moderator), vannak.heng, emma.wilson and liam.nguyen. The full list is at /users (field username); logging in with the email works too.
A typical login flow
1. POST the form to /auth/login and store accessToken and refreshToken in secure storage (Keychain, EncryptedSharedPreferences or flutter_secure_storage). 2. Send the access token as a Bearer header on every request. 3. When a request returns 401 with token_expired, call /auth/refresh once and retry. 4. If refresh fails too, send the user back to the login screen.
Log in with "expiresInMins": 1 to see the expiry path within a minute.
Frequently asked questions
Are the tokens real JWTs?
Yes, HS256-signed JWTs you can decode on jwt.io. The secret is public, so they are only for testing.
Can I register new users?
POST /users returns a new user object, but it is not saved, so it cannot log in. Use the demo accounts.
Does logout exist?
With JWTs, logging out means deleting the tokens on the device. There is nothing to call on the server.
Why do I get 401 invalid_token?
The header must be exactly Authorization: Bearer <accessToken>. A refresh token or an edited token is rejected.