private static String composeRawResponse(
            boolean active, @Nullable String scope, @Nullable String clientId,
            @Nullable String userName, @Nullable String tokenType,
            @Nullable Instant expiresAt, @Nullable Instant issuedAt,
            @Nullable Instant notBefore, @Nullable String subject,
            @Nullable String audience, @Nullable String issuer,
            @Nullable String jwtId, Map<String, String> extras) {

        final ObjectNode node = JSON.createObjectNode();
        node.put(ACTIVE, active);
        if (scope != null) {
            node.put(SCOPE, scope);
        }
        if (clientId != null) {
            node.put(CLIENT_ID, clientId);
        }
        if (userName != null) {
            node.put(USER_NAME, userName);
        }
        if (tokenType != null) {
            node.put(TOKEN_TYPE, tokenType);
        }
        if (expiresAt != null) {
            node.put(EXPIRES_AT, expiresAt.getEpochSecond());
        }
        if (issuedAt != null) {
            node.put(ISSUED_AT, issuedAt.getEpochSecond());
        }
        if (notBefore != null) {
            node.put(NOT_BEFORE, notBefore.getEpochSecond());
        }
        if (subject != null) {
            node.put(SUBJECT, subject);
        }
        if (audience != null) {
            node.put(AUDIENCE, audience);
        }
        if (issuer != null) {
            node.put(ISSUER, issuer);
        }
        if (jwtId != null) {
            node.put(JWT_ID, jwtId);
        }
        extras.forEach(node::put);

        try {
            return JSON.writeValueAsString(node);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
Composes {@code JSON}-formatted raw Token Introspection Response body based on the other
{@link OAuth2TokenDescriptor} values.
oauth2/src/main/java/com/linecorp/armeria/common/auth/oauth2/OAuth2TokenDescriptor.java