LINE OA Verification
Overview
POST /api/line-oa/verify lets an external system holding an api-key confirm which LINE OA its
credentials are bound to, and whether that matches the OA it expects.
The caller submits a LINE OA channelId (optionally with channelSecret). The service searches
the line_oa.line_login_info JSONB column and compares the OA it finds against the caller's
api_key.line_oa_id. A match passes; a mismatch or a miss returns 404.
This feature has one important side effect: on every call it attempts, on a best-effort basis, to seed four starter audiences for the caller. As a result, the endpoint is commonly used as the "getting started" call that partners make first during onboarding.
Business Flow
- The request passes through the api-key middleware (see
API Key Authentication), yielding
apiClientIdandapiKey. - Loosely bind the body — the original had no DTO — reading
channelIdand the optionalchannelSecret. A malformed or empty body simply leaves zero values in place and execution continues, ultimately ending in a404. - Step 1 — resolve the
api_keyrow withSELECT ... FROM api_key WHERE api_client_id=$1 AND key=$2 AND status='active'. A genuine database error surfaces as500, not404. - Step 2 — find the LINE OA from JSONB with
SELECT ... FROM line_oa WHERE line_login_info->>'channelId' = $1. When the body supplieschannelSecret, the predicateAND line_login_info->>'channelSecret' = $2is appended. Text extraction replaces the original TypeORM object-equality comparison so that an index can be used. - Step 3 — seed the audience templates on a best-effort basis by calling
audience.Service.CreateAudienceTemplate(apiClientId, apiKey), which creates themookept-1throughmookept-4slugs when they do not yet exist (see Managing Audience Members via Public API). Errors here are swallowed, matching the original try/catch, and thedatafield comes back asnull. - Step 4 — compare the identifiers:
- If
lineOa.IDequalsapiKeyEntity.LineOaID, respond200with{code:"RES_SUCCESS_001", message:"verify success", data:(audience list)}. - On a mismatch, or if either side is missing, respond
404with the message"Channel ID and Channel Secret is required"(originally codedLINE_OA_001).
- If
:::note Two things worth knowing
- Seeding happens before the verification check. Calling with the wrong
channelIdstill seeds audiences for the caller before the404is returned — deliberate parity with the original execution order. - The Go port's error envelope follows the standard NestJS shape,
{statusCode, message, error}. Thecodepassed toNewExceptionis dropped, as documented in a comment onhttpx.NewException. :::
Key Files & Functions
| Method | Route | Auth | Handler |
|---|---|---|---|
| POST | /api/line-oa/verify | api-key | Handler.verify |
All source lives under internal/lineoa/.
| File | Highlights |
|---|---|
handler.go | Register (wrapped in deps.APIKeyAuth()), Handler.verify, caller, type verifyBody, audienceTemplateAdapter |
service.go | Service.Verify(ctx, apiClientID, apiKey, channelID, channelSecret), type VerifyResult, interfaces scopeResolver / lineOaFinder / templateCreator |
repository.go | Repository.FindByLineLoginInfo(ctx, channelID, channelSecret *string) — the JSONB predicate |
entity.go | struct LineOa (22 columns) and LineLoginInfo (jsonb Scanner/Valuer) |
channelSecret is intentionally a *string: omitting it drops the second predicate entirely,
which differs from passing an empty string that would be compared against ''.
Connections to Other Services
- Postgres — the
line_oatable (JSONB columnline_login_info), plusapi_key,api_client, andaudience, all accessed via the pgx simple protocol. That protocol choice is critical for JSONB and enum binding; see Core HTTP & Database Access. - The in-process
audiencemodule —lineoa.Registerconstructs its ownaudience.Servicein order to callCreateAudienceTemplate, which is why AMQP and exchange configuration must be present even though this path never publishes a message. - cms-api — the
line-oa-managementmodule owns the contents ofline_oa.line_login_info(channelId,channelSecret,lineLiffId,formLiffId), whileapi-keyissues the caller's key. - Related database domains:
line-oa-channel,api-client-key, andaudience. - No Redis or RabbitMQ is used on the verify path itself, aside from the dependencies the audience service brings along.