# How LINEJS Authentication and Token Refresh Work: A Complete Technical Guide

> Learn how LINEJS authentication and token refresh work. Discover how LINEJS automatically refreshes your tokens using authToken and refreshToken for uninterrupted access.

- Repository: [Evex  Developers/linejs](https://github.com/evex-dev/linejs)
- Tags: deep-dive
- Published: 2026-03-01

---

**LINEJS handles authentication by storing a short-lived `authToken` and long-lived `refreshToken`, automatically detecting expiration via `MUST_REFRESH_V3_TOKEN` errors and seamlessly refreshing tokens without user intervention.**

The LINEJS library (`evex-dev/linejs`) provides a robust authentication system for the LINE messaging API. Understanding how LINEJS manages authentication and token refresh is essential for building reliable bots and clients that maintain persistent connections without manual re-authentication.

## Understanding the LINEJS Authentication Model

LINEJS implements a dual-token architecture that separates short-term access from long-term session persistence.

### Token Storage Architecture

The client maintains two critical pieces of authentication data:

- **`authToken`** – Stored in `BaseClient.authToken` and exposed via `Client.authToken`. This short-lived LINE access token is sent as the `x-line-access` header in every HTTP request.
- **`refreshToken`** – Persisted in the client's storage layer under the key `"refreshToken"`. This long-lived token enables the acquisition of new `authToken` values when the current one expires.

Both tokens are emitted through the **`update:authtoken`** event, allowing applications to react to authentication state changes.

### Event-Driven Token Updates

The authentication system uses an event-based pattern defined in [`packages/linejs/base/core/utils/events.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/core/utils/events.ts). When tokens change, the client emits events that consuming applications can listen to for persistence or UI updates.

## Initial Login and Token Acquisition

The login logic resides in [`packages/linejs/base/login/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/login/mod.ts), which handles multiple authentication methods.

### Password-Based Authentication

The `withPassword` method executes the following sequence after successful credential validation:

1. Calls `client.auth.refresh` to obtain initial tokens
2. Extracts the `accessToken` and `refreshToken` from the response
3. Stores the `authToken` in memory and emits the `update:authtoken` event
4. Persists the `refreshToken` to storage for future use

```typescript
// Simplified flow from login/mod.ts (lines 140-155)
this.client.authToken = tokenInfo[1];               // access token
this.client.emit("update:authtoken", tokenInfo[1]);
await this.client.storage.set("refreshToken", tokenInfo[2]); // refresh token

```

### QR Code and Direct Token Login

QR-code login follows an identical token storage path once the QR flow completes. Direct auth-token login bypasses server contact and immediately emits the supplied token via the `update:authtoken` event.

All login methods converge on `Login.login()`, which calls `this.ready()` to fetch the user profile and emit the `"ready"` event.

## Automatic Token Refresh Mechanism

LINEJS implements transparent token refresh that requires no manual intervention from consuming applications.

### Detecting Token Expiration

The `RequestClient` in [`packages/linejs/base/request/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/request/mod.ts) monitors server responses for the specific error code `MUST_REFRESH_V3_TOKEN`:

```typescript
// From request/mod.ts (lines 24-28)
const isRefresh = Boolean(
  res.data.e &&
  res.data.e.code === "MUST_REFRESH_V3_TOKEN" &&
  await this.client.storage.get("refreshToken"),
);

```

When this error occurs and a `refreshToken` exists in storage, the client triggers automatic refresh.

### The Refresh Token Flow

`AuthService.tryRefreshToken()` in [`packages/linejs/base/service/auth/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/auth/mod.ts) handles the exchange:

```typescript
// From auth/mod.ts (lines 20-34)
public async tryRefreshToken() {
  const refreshToken = await this.client.storage.get("refreshToken");
  if (typeof refreshToken === "string") {
    const RATR = await this.refresh({ request: { refreshToken } });
    this.client.authToken = RATR.accessToken;
    this.client.emit("update:authtoken", RATR.accessToken);
    await this.client.storage.set(
      "expire",
      (RATR.tokenIssueTimeEpochSec as number) +
      (RATR.durationUntilRefreshInSec as number) as number,
    );
  } else {
    throw new InternalError("RefreshError", "refreshToken not found");
  }
}

```

This method calls the LINE endpoint `/EXT/auth/tokenrefresh/v1`, updates the in-memory `authToken`, emits the change event, and stores the new expiration timestamp.

### Request Retry Logic

After successful refresh, `RequestClient.requestCore()` automatically retries the original request with the new token:

```typescript
// From request/mod.ts (lines 51-62)
if (isRefresh && !isReRequest) {
  await this.client.auth.tryRefreshToken();
  return this.requestCore(
    path, value, methodName, protocolType,
    appendHeaders, overrideMethod, parse, true,
  );
}

```

The `true` flag passed as the final argument marks this as a re-request, preventing infinite refresh loops.

## Implementing Token Event Listeners

Applications should listen to the `update:authtoken` event to persist tokens or update UI state:

```typescript
client.on("update:authtoken", (newToken) => {
  // Update UI, store in secure storage, etc.
  console.log("Access token refreshed:", newToken);
});

```

The `end` event signals complete session termination when requests fail with `NOT_AUTHORIZED_DEVICE`, indicating the refresh token itself is invalid and manual re-authentication is required.

## Summary

- **Dual-token architecture**: LINEJS stores a short-lived `authToken` for requests and a long-lived `refreshToken` for renewal.
- **Automatic detection**: The client monitors for `MUST_REFRESH_V3_TOKEN` errors in [`packages/linejs/base/request/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/request/mod.ts).
- **Seamless refresh**: `AuthService.tryRefreshToken()` in [`packages/linejs/base/service/auth/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/auth/mod.ts) exchanges the refresh token and retries failed requests automatically.
- **Event-driven updates**: The `update:authtoken` event notifies applications of token changes for persistence or UI updates.

## Frequently Asked Questions

### How does LINEJS detect when an access token expires?

LINEJS detects expired tokens by monitoring HTTP responses for the specific error code `MUST_REFRESH_V3_TOKEN`. When `RequestClient` in [`packages/linejs/base/request/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/request/mod.ts) receives this error and finds a stored `refreshToken`, it automatically triggers the refresh flow without throwing an error to the calling code.

### What happens if the refresh token is invalid or missing?

If the refresh token is missing or invalid, `AuthService.tryRefreshToken()` throws an `InternalError` with the code `"RefreshError"`. Additionally, if a request fails with `NOT_AUTHORIZED_DEVICE`, the client emits the `"end"` event, signaling that the session has terminated and the user must re-authenticate manually.

### Can I manually trigger a token refresh in LINEJS?

Yes, you can manually trigger a refresh by calling `client.auth.tryRefreshToken()`. This method is public and available in [`packages/linejs/base/service/auth/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/auth/mod.ts). It retrieves the stored refresh token, calls the LINE `/EXT/auth/tokenrefresh/v1` endpoint, and updates the client's `authToken` while emitting the `update:authtoken` event.

### How should I persist authentication tokens between application restarts?

Listen to the `update:authtoken` event to save the access token, and ensure your storage backend persists the `refreshToken` (stored under the key `"refreshToken"`). When initializing the client, populate the storage with the saved refresh token so that `AuthService.tryRefreshToken()` can function if the access token expires during the session.