# 8.3 File Upload route permissions issue

**URL:** <https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007>\
**Category:** Module Development\
**Created:** [November 6, 2025, 4:40pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007 "2025-11-06T16:40:50Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Serghei\_Luchianov](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Serghei\_Luchianov](https://forum.inductiveautomation.com/u/Serghei_Luchianov)\
**Post date:** [November 6, 2025, 4:40pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/1 "2025-11-06T16:40:50Z")

</div>

Hi,  
We’ve run into a permission issue when updating our module to 8.3  
Out SNMP module has a setting for uploading and listing additional configuration files like so:

> ```
> // Upload MIB files
> 
> this.routeGroup.newRoute("/mib/upload")
> 
> .method(HttpMethod.POST)
> 
> .type("application/json")
> 
> .nocache()
> 
> .handler(this::uploadMibFiles)
> 
> .requirePermission(PermissionType.WRITE)
> 
> .mount();
> 
> // List uploaded MIB files
> 
> this.routeGroup.newRoute("/mib/list")
> 
> .method(HttpMethod.GET)
> 
> .type("application/json")
> 
> .nocache()
> 
> .handler(this::listMibFiles)
> 
> .requirePermission(PermissionType.READ)
> 
> .mount();
> 
> ```

We then have a GET and a POST in our react code to list uploaded files and upload them respectively:

> ```
> getMibFiles: builder.query<MibFileListResponse, void>({
> 
> query: () => \`/data/snmp/mib/list\`,
> 
> }),
> 
> uploadMibFiles: builder.mutation<UploadResponse, FormData>({
> 
> query: (formData) => ({
> 
> url: \`/data/snmp/mib/upload\`,
> 
> method: "POST",
> 
> body: formData,
> 
> }),
> 
> }),
> 
> ```

While listing files works without a hitch, when uploading a file, we receive a 403 response from the gateway. There is nothing in the gateway log. It seems that the problem stems from the:

requirePermission(PermissionType.WRITE)

If we try to change this permission, the route mounting fails Ignition’s internal validation as unsafe, and the routes don’t mount at all.

Are we missing something in our route setup or mounting?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 6, 2025, 4:43pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/2 "2025-11-06T16:43:57Z")

</div>

`PermissionType.WRITE` implicitly declares that the incoming request must be authorized with the gateway write permission (set in your gateway security settings), by either a logged in user session, a valid API key, or a security zone based permission.

If you don't want to use those or want to provide your own access control, use `RouteMounter.accessControl` instead. If you want to make a totally public route, pass `AccessControlStrategy.OPEN_ROUTE` in the `accessControl` builder method.

---

<div class="post-metadata">

**Author:** ![Serghei\_Luchianov](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Serghei\_Luchianov](https://forum.inductiveautomation.com/u/Serghei_Luchianov)\
**Post date:** [November 6, 2025, 4:48pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/3 "2025-11-06T16:48:04Z")

</div>

That’s kind of the problem, since the requests are done under an authenticated user with the Administrator role, which has the write permissions.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 6, 2025, 6:33pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/4 "2025-11-06T18:33:47Z")

</div>

Ah, okay, Perspective works differently (because it's not part of platform).

So if you're in a module that depends on Perspective you should have `com.inductiveautomation.perspective.gateway.comm.Routes` on your classpath - that class has a utility method you can use:  
[`requireSession`](https://files.inductiveautomation.com/sdk/javadoc/ignition83/8.3.0/com/inductiveautomation/perspective/gateway/comm/Routes.html#requireSession(java.util.EnumSet)) method you can use - just pass in the "session scopes" (runtime session or designer) allowed.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 6, 2025, 7:45pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/5 "2025-11-06T19:45:57Z")

</div>

This is an SNMP module, not anything to do with Perspective.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 6, 2025, 8:07pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/6 "2025-11-06T20:07:34Z")

</div>

Okay, last try (too distracted today).

The POST is likely failing because it's missing a CSRF token implicitly required by 'unsafe' HTTP methods and required by the `WRITE` PermissionType.

`com.inductiveautomation.ignition.gateway.web.session.WebUiSession#CSRF_TOKEN_HEADER`

The CSRF token for your current session can be retrieved from `/data/app/session`.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 6, 2025, 8:10pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/7 "2025-11-06T20:10:43Z")

</div>

Heh. I thought so. I figured out I would need a csrf token by watching the headers in the network tab of a session while editing the IA native modbus driver's address map. Now I know where to find it for my own use...

{Wrapping up my v8.3 module conversions soon.}

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 12, 2025, 10:19pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/8 "2025-11-12T22:19:09Z")

</div>

> [@paul-griffith](#):
>
> The CSRF token for your current session can be retrieved from `/data/app/session`.

I banged my head on this. Wrong approach, apparently. My IDE is happy with this:

```python
const csrf = useSelector((store: ReduxRootState) => store.userSession.csrfToken);

```

Will test tomorrow. My brain is fried for the day.

---

<div class="post-metadata">

**Author:** ![Serghei\_Luchianov](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Serghei\_Luchianov](https://forum.inductiveautomation.com/u/Serghei_Luchianov)\
**Post date:** [November 12, 2025, 11:13pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/9 "2025-11-12T23:13:21Z")

</div>

We got it working.

Your react code needs something like this:

> async function getCsrfToken(): Promise\<string | null\> {
> 
> if (cachedCsrfToken) {
> 
> ```
> return cachedCsrfToken;
> 
> ```
> 
> }
> 
> try {
> 
> ```
> const response = await fetch("/data/app/session");
> 
> if (response.ok) {
> 
> const data = await response.json();
> 
> cachedCsrfToken = data.csrfToken || null;
> 
> return cachedCsrfToken;
> 
> }
> 
> ```
> 
> } catch (error) {
> 
> ```
> console.error("Failed to fetch CSRF token:", error);
> 
> ```
> 
> }
> 
> return null;
> 
> }

Then you place that in the header like so:

> const csrfToken = await getCsrfToken();
> 
> ```
> if (csrfToken) {
> 
> headers.set("x-csrf-token", csrfToken);
> 
> }
> 
> ```

Regards,  
Serghei

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 12, 2025, 11:19pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/10 "2025-11-12T23:19:45Z")

</div>

I couldn't convince myself I actually needed to fetch from that route, since the session store already in the browser shows that it already knows the CSRF token. The one-liner I show replaces your fetching and caching operations.

---

<div class="post-metadata">

**Author:** ![Serghei\_Luchianov](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Serghei\_Luchianov](https://forum.inductiveautomation.com/u/Serghei_Luchianov)\
**Post date:** [November 12, 2025, 11:21pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/11 "2025-11-12T23:21:57Z")

</div>

So, there are two different csrf tokens. I’ve done a comparison, and the one in the cookies doesn’t match the one in the data/app/session 🤷🏽‍♂️

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 12, 2025, 11:23pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/12 "2025-11-12T23:23:36Z")

</div>

I'm not getting it from the cookies. I'm getting it from the react-redux session.

---

<div class="post-metadata">

**Author:** ![Serghei\_Luchianov](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Serghei\_Luchianov](https://forum.inductiveautomation.com/u/Serghei_Luchianov)\
**Post date:** [November 12, 2025, 11:26pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/13 "2025-11-12T23:26:04Z")

</div>

I would suggest confirming that the csrf token in react-redux session is the same as one in /data/app/session. If there are 2 different tokens, there could be 3 different tokens.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 13, 2025, 4:59pm UTC](https://forum.inductiveautomation.com/t/8-3-file-upload-route-permissions-issue/112007/14 "2025-11-13T16:59:28Z")

</div>

My retrieval of the token from the react-redux store worked just fine.

As did the rest of the config file import process, so the end of the tunnel for my beta drivers is in sight. 😁
