Skip to content

Navigation Menu

Sign in
Sign up

Authentication #164

PeterGumball started this conversation in General
Mar 20, 2026 · 2 comments · 5 replies
Discussion options

Hello Tunay. I hope you're doing well.

It's so quiet here; I'll start a new discussion 😀

I've just implemented a basic authentication, following the example project under "https://github.com/Tuntii/RustAPI-examples/tree/main/auth-api".

Unfortunately, I keep getting the error:

{"error":{"type":"unauthorized","message":"No authenticated user. Did you forget to add JwtLayer middleware?"},"error_id":"err_3f3b5304cda046d18900fec6327bfa0d"}

Any Ideas? Did I forget something?

You can test it with my code on codeberg under the branch "authentication"

You must be logged in to vote

Replies: 2 comments 5 replies

Comment options

Hey @Tuntii.

Any ideas?

You must be logged in to vote
2 replies
Comment options

I was dealing with family issues and my own business. I know how to fix the issue; I'll take a look at Codeberg. I was having the same problem in the example

Comment options

Hi Tunay,

I hope you and your family are doing well. Have you had a chance to take a look at the problem yet?

Take your time, but I hope you don’t give up on the project. I really like it.

All the best,
Peter

Comment options

Hi Peter! Sorry for the long delay, and thanks for your patience.

I tracked this down, and the problem is most likely not your token generation or the AuthUser extractor itself.

The issue is the skip_paths(...) configuration. Right now the JWT layer treats skip entries as path prefixes, so if "/" is included, it matches every route including /protected/profile.

That means the middleware skips JWT validation for the protected routes as well, so no validated claims are inserted into the request. Then AuthUser<Claims> fails with:

No authenticated user. Did you forget to add JwtLayer middleware?

Immediate fix

Please remove "/" from the skip list and keep only the truly public paths, for example:

.layer(
 JwtLayer::<Claims>::new(JWT_SECRET)
 .skip_paths(vec!["/health", "/docs", "/auth/login"])
)

After that, the protected routes should start receiving the authenticated claims correctly, assuming you are sending:

Authorization: Bearer <token>

Why this was confusing

The error message makes it look like the middleware is missing, but in this case the middleware is present it is just skipping the protected route because of the root path entry.

Maintainer-side follow-up

I’ve also fixed this on the framework side so that "/" only matches the exact root path instead of every route, and I added regression coverage for it.

So the short version is:

  • your auth flow is basically correct,
  • the misleading part is the skip_paths behavior,
  • and removing "/" from that list should solve the problem immediately.

If you want, paste your middleware setup here and I can sanity-check it line by line.

You must be logged in to vote
3 replies
Comment options

Hi Tunay,

It's great to hear from you. I'll take a look at it in the next few days and get back to you.

Comment options

Hi Tunay.

I have removed / from skip_path, now it works. 😁

Am I correct in thinking that, once the JWT layer is added, all endpoints require authentication, except for those listed in skip_path?

It would be nice if all endpoints were accessible without authentication, and only those with the AuthUser extractor were protected. Is that possible?

Comment options

Hi Peter, glad you got it working! 🎉

Your understanding is correct. JwtLayer is an opt-out guard: once added, every request must carry a valid Bearer token unless the path is listed in skip_paths.

The pattern you're describing opt-in auth, where only handlers that declare AuthUser<T> are gated is a different design. Right now it's not directly supported, but there are two practical paths:

Option 1: Use skip_paths for your public routes (current, works today):

.layer(JwtLayer::<Claims>::new(secret).skip_paths(vec!["/health", "/docs", "/api/v1/public"]))

Option 2: Feature request: "optional" / "soft" JWT mode
A JwtLayer::optional() mode could validate and inject claims when a token is present, but let requests through without one. Handlers with AuthUser<T> would then enforce the gate themselves (they already return 401 if no claims are in extensions). This would enable exactly the behavior you described.

If Option 2 sounds useful, feel free to open a feature request. it's a reasonable addition and the groundwork (ValidatedClaims in extensions, AuthUser returning ApiError::unauthorized) is already there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /