Apikeys end point always 404s

using 5.9.1

in my metadata, i can see this:

GetApiKeys

Requires Authentication

The following routes are available for this service:|All Verbs|/api/apikeys|||
| — | — | — | — |
|All Verbs|/api/apikeys/{Environment}|||

GetApiKeys Parameters:|NAME|PARAMETER|DATA TYPE|REQUIRED|DESCRIPTION|
| — | — | — | — | — |
|Environment|path|string|No||
|Meta|query|Dictionary<string, string>|No|

but every time i try to GET or POST to

https://aaaa:5000/api/apikeys

with or without environment, it is always throwing a 404 (in postman)

same thing happens if i am authed or not too.

why would it show up in metadata but 404? i can see the keys in my database

Please post the raw HTTP Headers for one of the failed requests.

in something like fiddler, or in SS itself via the request pipeline?

using this in Configure() results in nothing being seen

 this.GlobalRequestFilters.Add((req, res, requestDto) => 
 {
     Console.WriteLine(req.Headers.DumpTable());
 
 });

in Postman, the headers for the request look like:

if i hit another service (one i wrote) i see something like this:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET https://localhost:5000/api/client application/json 63
2020-08-07 07:57:29.4620 ServiceStack.Host.RestHandler.CreateRequestAsync Debug CreateRequestAsync/requestParams:

[Connection, keep-alive]
[Content-Type, application/json]
[Accept, application/json]
[Accept-Encoding, gzip, deflate, br]
[Cookie, ss-opt=perm; X-UAId=; ss-pid=odZbVHEN6AC6k9haZvz2]
[Host, localhost:5000]
[User-Agent, PostmanRuntime/7.26.2]
[Content-Length, 63]
[Postman-Token, d58d5eac-ebab-4f48-96e7-35dc58b4ee38]

and it returns a 200

when i try to hit /api/apikeys, it does not even register in the console short of:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET https://localhost:5000/api/apikeys
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 1.8355ms 404

if there is a better way to capture what you need, please let me know and i will do it asap.

i turned the ASP.net logging to trace for everything in appsettings and it didnt seem to get much more info:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET https://localhost:5000/api/apikeys
trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2]
All hosts are allowed.
dbug: Microsoft.AspNetCore.Server.Kestrel[9]
Connection id “0HM1QP8HSQOLG” completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 4.8358ms 404

i also do not see the requests coming in to https://localhost:5000/api/requestlogs

Operations Metadata shows this:

GetApiKeys GetApiKeysResponse GetApiKeysService ANY /apikeys, /apikeys/{Environment}

logs from Postman

GET /api/apikeys HTTP/1.1

Accept: application/json

User-Agent: PostmanRuntime/7.26.2

Postman-Token: aa1ee156-4dc0-4c46-8c0c-fbc6eea2b6a8

Host: localhost:5000

Accept-Encoding: gzip, deflate, br

Connection: keep-alive

Cookie: ss-opt=perm; X-UAId=; ss-pid=odZbVHEN6AC6k9haZvz2; ss-id=57uvoVHqrr9tg35mgfaa

HTTP/1.1 404 Not Found

Date: Fri, 07 Aug 2020 12:21:35 GMT

Server: Kestrel

Content-Length: 0

logs from fiddler when postman is using it for proxy:

GET https://localhost:5000/api/apikeys HTTP/1.1
Accept: application/json
User-Agent: PostmanRuntime/7.26.2
Postman-Token: 505b8109-12aa-4a5c-a7e6-3fbfd9fab869
Host: localhost:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: ss-opt=perm; X-UAId=; ss-pid=odZbVHEN6AC6k9haZvz2; ss-id=57uvoVHqrr9tg35mgfaa

in something like fiddler, or in SS itself via the request pipeline?

Using the Network WebInspector in Chrome or a HTTP Packet sniffer like Fiddler or WireShark.

This response suggests the request isn’t reaching ServiceStack:

HTTP/1.1 404 Not Found
Date: Fri, 07 Aug 2020 12:21:35 GMT
Server: Kestrel
Content-Length: 0

If you can compare it with a successful request it should hopefully be able to show you the difference between the requests.

Something about the request isn’t matching with the route. How are you configuring the /api path? Are you using the right scheme port? E.g. SSL is usually on port 5001, i.e https://localhost:5001.

Maybe you have a conflicting middleware that’s terminating /api/* requests before it reaches ServiceStack?

all my other services, including my own plus built in ones like AutoQuery, Register, etc work fine

app.UsePathBase("/api");

app.UseServiceStack(new AppHost
{
    PathBase = "/api",
    AppSettings = new NetCoreAppSettings(Configuration)
});

launchSettings looks like:

"applicationUrl": "https://localhost:5000"

here is a call to the Hello service

Warning: Unable to verify the first certificate

GET /api/hello/asdas HTTP/1.1
Content-Type: application/json
Accept: application/json
User-Agent: PostmanRuntime/7.26.2
Postman-Token: 123615f3-0e65-40ce-b6df-1755b39593a3
Host: localhost:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: ss-opt=perm; X-UAId=; ss-pid=odZbVHEN6AC6k9haZvz2; ss-id=57uvoVHqrr9tg35mgfaa

HTTP/1.1 200 OK
Date: Fri, 07 Aug 2020 13:17:52 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Vary: Accept
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD
Access-Control-Allow-Origin: *
X-Powered-By: ServiceStack/5.91 NetCore/Windows

{"result":"Hello, asdas!"}

this setup is as simple as it gets. default SS project, roll my own services, add plugins, etc. nothing crazy

Other SS setup info

 Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[]
    {
        new ApiKeyAuthProvider(AppSettings),
        new CustomBasicAuthProvider(), //Sign-in with HTTP Basic Auth
        new CustomCredentialsAuthProvider() //HTML Form post of UserName/Password
    })
    {
        IncludeRegistrationService = true
    });

Ideally it shouldn’t matter but can you remove the duplicate:

app.UsePathBase("/api");

Which is already registered by ServiceStack when you use PathBase = "/api", the double-entry could potentially cause a conflict.

Now that I’m looking at it, the issue could be because the /apikeys route starts with the same path as your /api PathBase, can you try calling it using the pre-defined route instead, e.g:

https://localhost:5000/api/json/reply/GetApiKeys

ok this works

https://localhost:5000/api/json/reply/GetApiKeys

where i do a GET and set

Environment:test

in x-www-form parameters

without that tho, it complains Environment is required, even when i do this:

https://localhost:5000/api/json/reply/GetApiKeys/test

when i remove the app.UsePathBase this still 404s

https://localhost:5000/api/apikeys

i did a test using this:

PathBase = “/test”,

and it worked! is this something that can be fixed with SS or do i need to choose something other than /api?

as a secondary issue, i never get back api keys, even tho there are several in the table.

when i auth and get a session back, then try apikeys/test, this sql ends up on the console:

2020-08-07 10:05:23.0504 ServiceStack.OrmLite.OrmLiteUtils.DebugCommand Debug SQL: SELECT “Id”, “UserAuthId”, “Environment”, “KeyType”, “CreatedDate”, “ExpiryDate”, “CancelledDate”, “Notes”, “RefId”, “RefIdStr”, “Meta”
FROM “ApiKey”
WHERE (“UserAuthId” is null) AND (“CancelledDate” is null) AND ((“ExpiryDate” is null) OR (“ExpiryDate” >= @0))
ORDER BY “CreatedDate” DESC
PARAMS: @0=8/7/2020 2:05:23 PM

why would it be looking for where UserAuthId is null? it does not appear to be looking at the environment either

dont i want the keys back for the authenticated user, or all the API keys? if i am using this wrong, please let me know

after i did a call to

https://localhost:5000/api1/apikeys/regenerate/test

a new api key showed up, without a userauthid

the call to /apikeys/test then shows this key in the response.

so i guess that leaves me with the question, how do users get their apikeys? do i need to roll a service for that, or add it to the session?

It doesn’t appear the request reaches ServiceStack so it’s not going to be something it can be changed to handle.

API Keys are generated for new users, see the docs for how to generate them for existing users:

Generating API Keys for Existing Users

using some of the api keys for a certain user, i have been able to get this to work.

https://localhost:5000/api1/server GET with bearer auth and the api key

with basic auth, the key as the username, it throws some crazy exception about s missing. The same thing happens if i use an apikey that has userAuthId == null

{
    "responseStatus": {

        "errorCode": "ArgumentNullException",

        "message": "Value cannot be null. (Parameter 's')",

        "stackTrace": "[ServerRequest: 8/7/2020 2:24:45 PM]:\n[REQUEST: {}]\r\nSystem.ArgumentNullException: Value cannot be null. (Parameter 's')\r\n   at System.Int32.Parse(String s)\r\n   at ServiceStack.Auth.OrmLiteAuthRepositoryBase`2.<>c__DisplayClass26_0.<GetUserAuth>b__0(IDbConnection db) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\Auth\\OrmLiteAuthRepository.cs:line 428\r\n   at ServiceStack.Auth.OrmLiteAuthRepository`2.Exec[T](Func`2 fn) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\Auth\\OrmLiteAuthRepository.cs:line 53\r\n   at ServiceStack.Auth.OrmLiteAuthRepositoryBase`2.GetUserAuth(String userAuthId) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\Auth\\OrmLiteAuthRepository.cs:line 426\r\n   at ServiceStack.Auth.UserAuthRepositoryExtensions.GetUserAuth(IAuthRepository authRepo, String userAuthId) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\UserAuthRepositoryExtensions.cs:line 172\r\n   at ServiceStack.Auth.ApiKeyAuthProvider.Authenticate(IServiceBase authService, IAuthSession session, Authenticate request) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\ApiKeyAuthProvider.cs:line 200\r\n   at ServiceStack.Auth.AuthenticateService.Authenticate(Authenticate request, String provider, IAuthSession session, IAuthProvider oAuthConfig) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\AuthenticateService.cs:line 411\r\n   at ServiceStack.Auth.AuthenticateService.Post(Authenticate request) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\AuthenticateService.cs:line 218\r\n   at ServiceStack.Auth.ApiKeyAuthProvider.PreAuthenticateWithApiKey(IRequest req, IResponse res, ApiKey apiKey) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\ApiKeyAuthProvider.cs:line 309\r\n   at ServiceStack.Auth.ApiKeyAuthProvider.PreAuthenticate(IRequest req, IResponse res) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\ApiKeyAuthProvider.cs:line 240\r\n   at ServiceStack.AuthenticateAttribute.PreAuthenticateAsync(IRequest req, IEnumerable`1 authProviders) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\AuthenticateAttribute.cs:line 153\r\n   at ServiceStack.AuthenticateAttribute.ExecuteAsync(IRequest req, IResponse res, Object requestDto) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\AuthenticateAttribute.cs:line 74\r\n   at ServiceStack.Host.ServiceRunner`1.ExecuteAsync(IRequest req, Object instance, TRequest requestDto) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Host\\ServiceRunner.cs:line 127\r\n",
        "errors": [
            {
                "errorCode": "ArgumentNullException",
                "fieldName": "s",
                "message": "Value cannot be null."
            }
        ]
    }
}

Re New user API key creation,

yes, and SS is doing this. i see them in the table, and the UserAuthId points to their Id in the Users table (i inherited UserAuth to add some fields). is SS looking for UserAuth vs my new name, User, or doesnt it matter?

The Exception is because the ApiKey doesn’t have a UserAuthId which is supposed to reference the User it should authenticate as.

I’ve updated the AuthProvider to check that the ApiKey has a UserAuthId otherwise it will throw a 409 Conflict “ApiKey is Invalid” error in the next version.

ok cool.

this still does not work tho:

auth and get a session back, then try

https://localhost:5000/capi/apikeys/test

i returns empty set. why would it not get me back the key for the auth user in the test environment (I authed as that user)?

Id UserAuthId Environment
KB_QK3F3yX_OMUrcCPVG9vl-M34Nboxj 2 test

thinking it may be old session related, i logged in as a different user and it still came back

{

"results": []

}

The GetApiKeys API just returns the API Keys for the authenticated user in the specified environment. I’m assuming the Authenticated User Id i.e. GetSession().UserAuthId doesn’t return “2”.

You can view the generated SQL that’s executed in the console in your AppHost.Configure() with:

OrmLiteUtils.PrintSql();

perfect. that was it. it makes sense why i saw authuserid == null in there before now. it was coming from the session

adding

session.UserAuthId = user.Id.ToString();

to my custom auth providers did the trick.

you have so much functionality in this thing sometimes its hard to wrap the mind around!

1 Like