# Authentication on custom data routes

**URL:** <https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962>\
**Category:** Module Development\
**Tags:** perspective, security\
**Created:** [February 27, 2025, 8:34am UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962 "2025-02-27T08:34:54Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Stian\_Strom](https://avatars.discourse-cdn.com/v4/letter/s/b38774/32.png) [@Stian\_Strom](https://forum.inductiveautomation.com/u/Stian_Strom)\
**Post date:** [February 27, 2025, 8:34am UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/1 "2025-02-27T08:34:54Z")

</div>

I've created a gateway-scoped module that has some data endpoints set up using mountRoutes in the GatewayHook.

I need to secure these endpoints so that only authenticated users can GET/POST data to them. I've looked into the restrict-method of the RouteMounter, and this works well when accessing the endpoints from a logged-in session on the gateway.

To begin with I need to be able to call the endpoints from Perspective views as well. These views are locked down. Is there a way to pass the credentials of the logged-in user to the endpoint?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [February 27, 2025, 12:47pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/2 "2025-02-27T12:47:48Z")

</div>

> [@Stian\_Strom](#):
>
> Is there a way to pass the credentials of the logged-in user to the endpoint?

You can pretty easily retrieve a `WebAuthStatus` by looking up a Perspective client’s session id with from the session monitor.

```kotlin
// Embr-SSE PerspectiveAuthRequest.kt
    override fun getSecurityContext(context: EventStreamGatewayContext): SecurityContext {
        return context.perspectiveContext?.run {
            logger.trace("Attempting to find Perspective Session {}...", sessionId)
            return sessionMonitor
                .findSession(UUID.fromString(sessionId))
                .map {
                    logger.trace("Perspective Session {} found.", it.sessionId)
                    SecurityContext.fromSecurityLevels(it.webAuthStatus.securityLevels)
                }
                .orElse(null)
        } ?: SecurityContext.emptyContext()
    }

```

---

<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:** [February 27, 2025, 12:56pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/3 "2025-02-27T12:56:06Z")

</div>

If a request comes from a Perspective session, the HttpSession will contain a `perspective-session` attribute of type `PerspectiveSessionCollection`. That object has a `.findProjectSession` which leads you to its `.getWebAuthStatus()`, to be used like the gateway's base auth status.

You will need to make your module depend on Perspective in order to be able to use those types.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [February 27, 2025, 12:58pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/4 "2025-02-27T12:58:04Z")

</div>

Ooh, that’s cool!

---

<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:** [February 27, 2025, 12:59pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/5 "2025-02-27T12:59:08Z")

</div>

Blob server uses that infra to honor a Named Query's security. There are some nuances to unauth sessions that fall into a security zone that I don't actually handle correctly. (I reject them.) You may need to poke around a bit.

---

<div class="post-metadata">

**Author:** ![Stian\_Strom](https://avatars.discourse-cdn.com/v4/letter/s/b38774/32.png) [@Stian\_Strom](https://forum.inductiveautomation.com/u/Stian_Strom)\
**Post date:** [February 27, 2025, 1:06pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/6 "2025-02-27T13:06:36Z")

</div>

Thanks, I'll have a look

---

<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:** [February 27, 2025, 1:15pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/7 "2025-02-27T13:15:12Z")

</div>

You may need to use `ScriptContext.defaultProject()`. I don't see an obvious way to identify the request's origin project from the PSC. (In the Blob server, I make the user supply it in the URL.)

---

<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:** [February 27, 2025, 3:37pm UTC](https://forum.inductiveautomation.com/t/authentication-on-custom-data-routes/102962/8 "2025-02-27T15:37:18Z")

</div>

N.B. that authentication on routes is one of the API breaking changes in 8.3.0; you now can provide either an `AccessControlStrategy` (broadly similar to `RouteAccessControl`) _or_ specify a `PermissionType` and automatically get (at time of writing) web UI, auth token, and security zone based access control:

```java
        /**
         * Adds an access control strategy to this route. If multiple access controls strategies are added,
         * only one must pass for the request to be allowed. In other words, the strategies are combined with an OR.
         * Use {@link AccessControlStrategy#OPEN_ROUTE} to allow all requests.
         * <p>
         * If no access control strategy is added, the route will always be denied.
         */
        RouteMounter accessControl(AccessControlStrategy accessControl);

        /**
         * Adds access control strategies to this route that will require that the permissions required for the
         * given access type are possessed by the calling client.
         */
        RouteMounter requirePermission(PermissionType permissionType);

```
