gRPC/Protobuf: ClientExtra trigger 403 Forbidden

41 views
Skip to first unread message

Ting Sheng Ong

unread,
Jun 11, 2026, 10:26:11 PM (9 days ago) Jun 11
to Tinode General
Hi, We are developing a Flutter client using gRPC/Protobuf to connect to the Tinode server. We are facing a dilemma with out-of-band file attachments: 1. If we publish messages WITHOUT the extra field: The server doesn't link the file to the message, and it gets deleted by the server's garbage collector.
2. If we publish WITH the extra field to register attachments, Example:
final extra = ClientExtra(attachments: [fileUrl]);
final msg = ClientMsg(pub: pub, extra: extra);
The message is rejected with code=403, text=permission denied. Is there any way to solve this issue? or turn off the garbage collector?

Gene

unread,
Jun 12, 2026, 1:03:38 AM (9 days ago) Jun 12
to Tinode General
Can you debug the issue a bit more? Look at the logs, both client- and server- side.
Message has been deleted

Ting Sheng Ong

unread,
Jun 12, 2026, 4:14:29 AM (9 days ago) Jun 12
to Tinode General
Without "extra" field, the attachment will get deleted in Minio after 1 hour
Client-side:
I/flutter (19632): 15:57:09.608 MAIN > INFO: [TinodeAttachmentService] Starting REST upload to xxxxxxxxxxxxxxxx/v0/file/u/: file=1000000695.jpg, mime=image/jpeg, size=171122 bytes
I/flutter (19632): 15:57:10.076 MAIN > INFO: [TinodeAttachmentService] POST upload response status: 200
I/flutter (19632): 15:57:10.078 MAIN > INFO: [TinodeService] Publishing attachment to topic usrsM65NyggZjI: file=1000000695.jpg, type=IM, msgId=media_-1781251029602
I/flutter (19632): 15:57:10.080 MAIN > FINE: [TinodeService] Sending ClientMsg: ClientMsg_Message.pub
I/flutter (19632): 15:57:10.190 MAIN > FINE: [TinodeService] Received ServerMsg: ServerMsg_Message.ctrl
I/flutter (19632): 15:57:10.190 MAIN > FINE: [TinodeService] Ctrl response: id=media_-1781251029602, code=202, text=accepted
I/flutter (19632): 15:57:10.191 MAIN > INFO: [TinodeService] Successfully published attachment to usrsM65NyggZjI

Server-side
I2026/06/12 07:57:09 media upload: ok GoQyNwMxRgc dkcdenydgfdao
I2026/06/12 07:57:09 grpc in: pub:{id:"media_-1781251029602"  topic:"usrsM65NyggZjI"  head:{key:"attachments"  value:"[\"/v0/file/s/GoQyNwMxRgc.jpeg\"]"}  head:{key:"mime"  value:"\"text/x-drafty\""}  content:"{\"txt\":\" \",\"fmt\":[{\"at\":0,\"len\":1,\"key\":0}],\"ent\":[{\"tp\":\"IM\",\"data\":{\"mime\":\"image/jpeg\",\"name\":\"1000000695.jpg\",\"ref\":\"/v0/file/s/GoQyNwMxRgc.jpeg\",\"size\":171122}}]}"} eUhVfb_ZS7Q

With "extra" field, status code 403 permission denied
Client-side
I/flutter (19632): 16:05:14.850 MAIN > INFO: [TinodeAttachmentService] Starting REST upload to  xxxxxxxxxxxxxxxx/v0/file/u/: file=1000000686.jpg, mime=image/jpeg, size=134199 bytes
I/flutter (19632): 16:05:15.667 MAIN > INFO: [TinodeAttachmentService] POST upload response status: 200
I/flutter (19632): 16:05:15.671 MAIN > INFO: [TinodeService] Publishing attachment to topic usrsM65NyggZjI: file=1000000686.jpg, type=IM, msgId=media_-1781251514793
I/flutter (19632): 16:05:15.677 MAIN > FINE: [TinodeService] Sending ClientMsg: ClientMsg_Message.pub
I/flutter (19632): 16:05:15.706 MAIN > FINE: [TinodeService] Received ServerMsg: ServerMsg_Message.ctrl
I/flutter (19632): 16:05:15.707 MAIN > FINE: [TinodeService] Ctrl response: id=, code=403, text=permission denied

Server-side
I2026/06/12 08:05:15 media upload: ok 2Z_cS_QedKg 3gp5ys7udz2kq
I2026/06/12 08:05:15 grpc in: pub:{id:"media_-1781251514793"  topic:"usrsM65NyggZjI"  head:{key:"attachments"  value:"[\"/v0/file/s/2Z_cS_QedKg.jpeg\"]"}  head:{key:"mime"  value:"\"text/x-drafty\""}  content:"{\"txt\":\" \",\"fmt\":[{\"at\":0,\"len\":1,\"key\":0}],\"ent\":[{\"tp\":\"IM\",\"data\":{\"mime\":\"image/jpeg\",\"name\":\"1000000686.jpg\",\"ref\":\"/v0/file/s/2Z_cS_QedKg.jpeg\",\"size\":134199}}]}"}  extra:{attachments:"/v0/file/s/2Z_cS_QedKg.jpeg"} t6IjP6qZ1cg
W2026/06/12 08:05:15 s.dispatch: non-root assigned asUser t6IjP6qZ1cg

Gene

unread,
Jun 12, 2026, 9:08:41 AM (9 days ago) Jun 12
to Tinode General
See here: value:"[\"/v0/file/s/GoQyNwMxRgc.jpeg\"]"
You are sending a string instead of an array.

Gene Sokolov

unread,
Jun 12, 2026, 9:27:01 AM (9 days ago) Jun 12
to tin...@googlegroups.com
BTW, most of what you are sending is malformed in the same way: you are double quoting strings, sending strings instead of json objects etc.

--
You received this message because you are subscribed to the Google Groups "Tinode General" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tinode+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/tinode/3e33f29c-98b3-40df-8615-937ec3a7a5e9n%40googlegroups.com.

Gene

unread,
Jun 12, 2026, 9:49:52 AM (9 days ago) Jun 12
to Tinode General

Gene

unread,
Jun 12, 2026, 9:53:35 AM (9 days ago) Jun 12
to Tinode General
And this is the reason why you are getting 403 (it has nothing to do with attachments):

W2026/06/12 08:05:15 s.dispatch: non-root assigned asUser t6IjP6qZ1cg

Ting Sheng Ong

unread,
Jun 12, 2026, 10:13:31 AM (9 days ago) Jun 12
to Tinode General
Got it, thanks for the response.

Ting Sheng Ong

unread,
Jun 14, 2026, 11:11:45 PM (6 days ago) Jun 14
to Tinode General
Here is the exact data my client side sends over the wire in the gRPC payload for pub messages:

I/flutter (18878): 10:29:47.420 MAIN > INFO: [TinodeAttachmentService] Starting REST upload to xxxxxxxxxxxxxxxxxxxx/v0/file/u/: file=1000000695.jpg, mime=image/jpeg, size=171122 bytes
I/flutter (18878): 10:29:47.918 MAIN > INFO: [TinodeAttachmentService] POST upload response status: 200
I/flutter (18878): 10:29:47.920 MAIN > INFO: [TinodeService] Publishing attachment to topic usrsM65NyggZjI: file=1000000695.jpg, type=IM, msgId=media_-1781490133266
I/flutter (18878): 10:29:47.923 MAIN > INFO: [TinodeService] Sending ClientMsg [pub]: id=media_-1781490133266, topic=usrsM65NyggZjI, head={mime: "text/x-drafty", attachments: ["/v0/file/s/lbPv-f6sQ8I.jpeg"]}, content={"txt":" ","fmt":[{"at":0,"len":1,"key":0}],"ent":[{"tp":"IM","data":{"mime":"image/jpeg","name":"1000000695.jpg","ref":"/v0/file/s/lbPv-f6sQ8I.jpeg","size":171122}}]}
I/flutter (18878): 10:29:47.925 MAIN > INFO: [TinodeService]   extra: attachments=[/v0/file/s/lbPv-f6sQ8I.jpeg], onBehalfOf=, authLevel=NONE
I/flutter (18878): 10:29:47.958 MAIN > FINE: [TinodeService] Received ServerMsg: ServerMsg_Message.ctrl
I/flutter (18878): 10:29:47.959 MAIN > FINE: [TinodeService] Ctrl response: id=, code=403, text=permission denied
I/flutter (18878): 10:30:02.928 MAIN > SEVERE: [TinodeService] Publish attachment to usrsM65NyggZjI timed out or failed.

This is server side
I2026/06/15 02:29:47 media upload: ok lbPv-f6sQ8I swz676p6vrb4e
I2026/06/15 02:29:47 grpc in: pub:{id:"media_-1781490133266"  topic:"usrsM65NyggZjI"  head:{key:"attachments"  value:"[\"/v0/file/s/lbPv-f6sQ8I.jpeg\"]"}  head:{key:"mime"  value:"\"text/x-drafty\""}  content:"{\"txt\":\" \",\"fmt\":[{\"at\":0,\"len\":1,\"key\":0}],\"ent\":[{\"tp\":\"IM\",\"data\":{\"mime\":\"image/jpeg\",\"name\":\"1000000695.jpg\",\"ref\":\"/v0/file/s/lbPv-f6sQ8I.jpeg\",\"size\":171122}}]}"}  extra:{attachments:"/v0/file/s/lbPv-f6sQ8I.jpeg"} 8us6qsubZ0Y
W2026/06/15 02:29:47 s.dispatch: non-root assigned asUser 8us6qsubZ0Y


im sure im not sending string
Could the 403 Forbidden error be related to how the server validates the ClientExtra fields in session.go?
Specifically, when the Dart client instantiates ClientExtra, the Protobuf library automatically serializes the default unassigned fields (auth_level: NONE and on_behalf_of: "") into the binary payload. (This is because auth_level is defined as a Protobuf enum where NONE = 0 is the default value).
On the server side, session.go
Screenshot 2026-06-15 110828.png
Since the client sends the default enum value NONE, the server parses msg.Extra.AuthLevel as "NONE". Because "NONE" is not an empty string "", it seems the first condition evaluates to false, which then triggers the root check for standard users.

Is this the expected behavior, and should standard clients explicitly clear/omit these default fields from ClientExtra before sending to avoid the root check?

ice Savage

unread,
Jun 14, 2026, 11:18:04 PM (6 days ago) Jun 14
to tin...@googlegroups.com
I can definitely fix this 

Ting Sheng Ong

unread,
Jun 14, 2026, 11:30:13 PM (6 days ago) Jun 14
to Tinode General
thanks, please let me know when the fix is available

Ting Sheng Ong

unread,
Jun 14, 2026, 11:31:39 PM (6 days ago) Jun 14
to Tinode General
any estimate on when it might be ready?

Gene S

unread,
Jun 15, 2026, 7:58:57 AM (6 days ago) Jun 15
to tinode
Please open a bug on GitHub


Gene

unread,
Jun 15, 2026, 2:56:39 PM (6 days ago) Jun 15
to Tinode General

Ting Sheng Ong

unread,
Jun 15, 2026, 9:09:22 PM (5 days ago) Jun 15
to Tinode General
Hi, thanks for the fix. Could you please update the container registry with this fix so we can pull the latest image and test it? Much appreciated!
Reply all
Reply to author
Forward
0 new messages