Skip to content
AniLink

MAL authentication

MAL uses OAuth2 with PKCE. Register an application at the MAL API panel to get a client ID.

1. Build the authorization URL

typescript
import { buildMalAuthorizationUrl } from "anilink-api-wrapper";

const codeVerifier = createPkceVerifier(); // your PKCE verifier (43-128 chars)
const authorizeUrl = buildMalAuthorizationUrl("mal-client-id", codeChallenge, "csrf-state");
// Redirect the user to `authorizeUrl`.

buildMalAuthorizationUrl(clientId, codeChallenge, state?) takes the S256 code challenge derived from your verifier. The optional state is CSRF protection — validate it on the redirect before exchanging the code.

2. Exchange the code

typescript
import { getMalAccessToken, AniLink } from "anilink-api-wrapper";

const token = await getMalAccessToken({
    clientId: "mal-client-id",
    code, // the `code` query parameter from the redirect
    codeVerifier, // the original verifier
    // clientSecret: "optional", // only for applications that use one
});

const aniLink = new AniLink({
    mal: { accessToken: token.access_token, refreshToken: token.refresh_token, clientId: "mal-client-id" },
});

Token requests use a default timeout of 10 seconds. Pass options on the request to override transport settings for the call.

3. Refresh before expiry

typescript
import { getMalTokenExpiry, refreshMalAccessToken } from "anilink-api-wrapper";

if (Date.now() >= getMalTokenExpiry(token).getTime() - 60_000) {
    const refreshed = await refreshMalAccessToken({
        clientId: "mal-client-id",
        refreshToken: token.refresh_token,
    });
    token = { ...refreshed, refresh_token: refreshed.refresh_token ?? token.refresh_token };
}

getMalTokenExpiry(response, now?) computes the absolute expiry from expires_in. The refresh response may omit refresh_token. Keep the stored one when it does (rotation semantics).

Constants and types

ExportValue / shape
MAL_API_BASE_URLhttps://api.myanimelist.net/v2
MAL_AUTHORIZE_URLhttps://myanimelist.net/v1/oauth2/authorize
MAL_TOKEN_URLThe MAL OAuth2 token endpoint
MAL_API_REFERENCELink to the MAL API v2 reference
MalTokenResponse{ access_token, token_type, expires_in, refresh_token?, scope? }
MalAuthorizationCodeRequest{ clientId, code, codeVerifier, clientSecret?, options? }
MalRefreshTokenRequest{ clientId, refreshToken, clientSecret?, options? }

Safe state validation

Generate a fresh random state per login attempt, store it server-side bound to the session, and compare with a timing-safe equality check before calling getMalAccessToken. Reject mismatches immediately.

Next steps

AniLink — typed AniList & MyAnimeList client for TypeScript.