json-rpc authentication?

6,912 views
Skip to first unread message

Roland Koebler

unread,
Oct 25, 2008, 7:36:50 AM10/25/08
to json...@googlegroups.com
hi,

how do you currently use authentication with json-rpc, or how would you
like to use it?

in my opinion, authentication normally consists of 3 parts:
1. login / create an auth-token
2. "authenticated" communication
3. logout / invalidate the auth-token

(1) and (3) can be done by using a simple json-rpc-method (e.g. 2
functions called "login" and "logout"), maybe in addition to timeouts
etc.

so, the main question is: where to put the authentication-token in (2)?


I can think of several ways:

a) authentication on function-level:
add an auth-token as e.g. 1st parameter to every function, like
proxy.myfunc(auth, parameter1, parameter2, ...)

this works great, especially if the functions need to know who called
them for a more detailed rights-management.

b) authentication on json-rpc-level:
add an (optional) field directly to json-rpc (this would be a json-rpc
extension), like:
'{"jsonrpc": "2.0", "method": "foo", "params": ..., "id": 1, "auth": "..."}'

I think that something like this would be quite useful.

c) authentication on transport-level:
e.g. BasicAuth with HTTP, but this only works if the transport
supports some authentication-scheme, and so it of course does
not work e.g. with pure socket-communication.


what do you think?
should we define an (optional) "authentication-field" for json-rpc?


regards,
Roland

Stephen McKamey

unread,
Oct 25, 2008, 11:52:45 AM10/25/08
to JSON-RPC
This is an excellent question and I really like the clarity of the
options presented.

IMHO, I think that having an option 'B' well defined would do a lot
for standardization of JSON-RPC auth where either 'C' isn't an option
or 'A' is cumbersome. In systems where 99% of communication is
authenticated, it feels like a lot of overhead to go with option 'A'.

I have been using JSON-RPC primarily in web browser/server scenarios,
so for me option 'C' has taken the form of auth via cookies. Most of
the time a UI is initially available which can be used to
authenticate. From there on a cookie maintains the token.

Having an option 'B' doesn't preclude the usage of 'A' or 'C' but
simply gives an alternative. For instance, if I used cookies 80% of
the time but some clients couldn't support it, I could then also look
in the auth field for the token. This makes it clean for a fallback
from 'C' without having to rework all of my method signatures.

Thanks,
smm

Jonas Wagner

unread,
Oct 25, 2008, 2:33:39 PM10/25/08
to JSON-RPC
I would do it at the Transport-Level, using Basic Auth or TLS for HTTP
and TLS for TCP.
Why? I think it's a bad idea to reinvent the wheel. Especially for
security critical stuff.

cheers,
Jonas

Kris Zyp

unread,
Oct 25, 2008, 2:47:09 PM10/25/08
to json...@googlegroups.com
I agree, I think this should be handled at the transport layer if it all
possible. As much as we can, I think we should avoid the temptation to
go beyond the scope of JSON-RPC in this specification, that is defining
how to do RPC with JSON. Orthogonal concerns (RPC and security) should
ideally be kept separate. For example with JSON-RPC, there may be other
messages being sent on the same transport in the same client-server
connection, it would certainly not be beneficial to have to use a
different authentication scheme for the JSON-RPC messages and other
messages.
If we truly feel that JSON-RPC simply must work on some transports
(real, used transports, theorizing about possible ones isn't helpful)
that can't provide authentication, then perhaps it is advisable to add
an optional parameter, but I would suggest the utmost caution in this
expansion in scope.
Kris

Stephen McKamey

unread,
Oct 25, 2008, 3:12:29 PM10/25/08
to JSON-RPC
I have no problem with this. My vote for 'B' (auth in the RPC
envelope) was merely to guide people to a common ground if 'A' (auth
method param) and 'C' (transport-based auth) didn't work. If the
general consensus is that 'C' (or 'C'-like mechanisms) will always
work for real transports, then 'B' really wouldn't be needed. My
feeling is still that 'A' is kind of ugly and muddies the concepts.

Matt (MPCM)

unread,
Oct 25, 2008, 10:41:23 PM10/25/08
to JSON-RPC
So far I have mainly used JSON-RPC in the http/https realm, using the
cookie mechanisms. The assumption being the transport can inject
something from the environment that represents authentication/session.
I am a proponent of `C` for the vast majority of uses. A modified
dispatch can easily reject method calls by users without permissions,
while exposing just the login or no-login-required methods.

For transports that have no such concept (or perhaps JSONRequest in
the future?), I think we are safe to do an extension spec to avoid `A`
and do `B`.

If you have influence over the client and don't want to mess with `B`,
you can do a double layered client->client-shim<->server-shim<-server.
Where the client-shim is a shim that wraps your real jsonrpc call as a
param and passes the auth token as the second param into a single
method on the server-shim, which if valid goes over to the real
server. JSON-RPC in JSON-RPC can be used for all sorts of fun things,
just need to be careful not to go too far down the rabbit hole.

For all versions of `A` and `B`, I see a strong need to be communicate
the *next* token back (assuming it is not a notification). The last
thing you want is people guessing your stale tokens (and yes, I do
this with cookie sessions on some systems).

Great topic for the group though :)

--
Matt (MPCM)

Skylos

unread,
Oct 26, 2008, 1:48:22 AM10/26/08
to json...@googlegroups.com
On Sat, Oct 25, 2008 at 4:36 AM, Roland Koebler <r.ko...@yahoo.de> wrote:

hi,

how do you currently use authentication with json-rpc, or how would you
like to use it?

When I was asked to add authentication to my json-rpc driven application, I utilized a cookie-like extension to json-rpc.

I have two main clients of my service - one is my home-grown json-rpc ajax calls in my web status/research application, and the second is utilizing JSON::RPC::Client from a few perl scripts.

I at first wanted to make it a different piece of the request object, but the client perl library I was using would require extension/hacking to make it work that way. 

I compromised by making a calling convention that requires the first parameter to be the authentication token.

I defined a method get_auth_token (token, username, password) that can be called, and doesn't require a token itself.

I created an expiring, md5-hash array utilizing a random string persistant private key to prevent manipulation.  (the string looks something like user:<username>:expires:<epochnum>:hash:<md5 string> - where <md5 string> is the md5 hash result of the same string with <md5 string> replaced with the private key.  Thus, I can validate it, and its contents are obvious for debugging purposes. (Unless they know my secret, of course)  There is no protection of the user/pass passing beyond transport security (https), but the security requirements here are more on the level of making it unobvious rather than truly secure.

I made the applications call get_auth_token and insert the returned token as the first parameter in the requests.

My server library was then wrapped in a class that extracts the token from the param string as well as defines the security levels for the various api calls - none, simple, full.  The web application was modified in a similar manner (since I wrote the rpc client function, it wasn't hard to insert the parameter)

It would be nifty to extend JSON::RPC::Server and JSON::RPC::Client to use such an arbitrary authentication mechanism... but then I'd like to completely re-write JSON::RPC::Server and client anyway - they don't seem to be written as base classes for object extension and that tweaks my preferred methodology of desiring call methods on an instantiated object, not on some kind of static state.  Maybe I missed something in how to use it, but sheesh.

Anyway, thats what I did.

David




Roland Koebler

unread,
Oct 26, 2008, 4:29:11 AM10/26/08
to json...@googlegroups.com
hi,

> I would do it at the Transport-Level, using Basic Auth

but basic auth only works for http.

> or TLS for HTTP and TLS for TCP.

no, that doesn't work. you can't use TLS for (user-)authentication or
session-management. TLS-authentication is based on certificates, and you
can't replace logins/sessionids/etc. with certificates.
so, "doing it on the transport-level" doesn't work for "pure" TCP.


regards,
Roland

Roland Koebler

unread,
Oct 26, 2008, 4:33:27 AM10/26/08
to json...@googlegroups.com
hi,

> If we truly feel that JSON-RPC simply must work on some transports
> (real, used transports, theorizing about possible ones isn't helpful)
> that can't provide authentication,

yes, JSON-RPC must work on transports which don't provide
authentication, e.g. unix domain sockets or TCP sockets.
and yes, they are really used.

regards,
Roland

Roland Koebler

unread,
Oct 26, 2008, 4:44:30 AM10/26/08
to json...@googlegroups.com
hi,

> If the
> general consensus is that 'C' (or 'C'-like mechanisms) will always
> work for real transports, then 'B' really wouldn't be needed.

no, 'C' doesn't work on e.g. TCP.

> My feeling is still that 'A' is kind of ugly and muddies the concepts.

that depends.
sometimes, 'A' can be quite useful and clean, e.g. if the called
functions need to know who called them. the functions then anyway
need some kind of user/role/auth-parameter, and then it's probably
the cleanest way to use 'A', since that doesn't change the syntax
of these functions. I'm currently using this, and it works great.

(but in other cases, using 'A' may be cumbersome, and that was
reason why I asked for 'B'.)


regards,
Roland

Jonas Wagner

unread,
Oct 26, 2008, 10:14:39 AM10/26/08
to JSON-RPC
Hi Roland,

On Oct 26, 10:29 am, Roland Koebler <r.koeb...@yahoo.de> wrote:
> hi,
>
> > I would do it at the Transport-Level, using Basic Auth
>
> but basic auth only works for http.
>
> > or TLS for HTTP and TLS for TCP.
>
> no, that doesn't work. you can't use TLS for (user-)authentication or
> session-management. TLS-authentication is based on certificates, and you
> can't replace logins/sessionids/etc. with certificates.

TLS does also support pre-shared keys - See RFC 4279, as well as other
authentication methods.
And for "pure" TCP, if you ask me, sending passwords over unprotected
connections is a bad idea.
You could still use TLS with a preshared key and NULL encryption.

For Unix Sockets there are credentials as well. I guess you could even
use TLS over them.
But I don't think json-rpc over unix domain socket is used all that
often.

The benefit I see from A) and B) is that they are transport agnostic,
which might be useful in some cases.
In those cases I'd probably use A) and just write a wrapper that
inserts the authtoken as first parameter of every request.
At least in dynamic languages that's really easy to do.

- Jonas

Stephen McKamey

unread,
Oct 26, 2008, 1:59:12 PM10/26/08
to JSON-RPC
Often times the systems that use a cookie-based auth mechanism ('C')
provide a way of statically inspecting the current user/session/
state. The method can then still know who called while keeping the
method signature independent of authentication/authorization. This
idea could easily be adapted for non-cookied transport auth.

For instance in the web world, ASP.NET uses a thread id based lookup
to get the current user. Auth decode of the cookie happens early in
the request pipeline, automatically filtering out unauthorized users,
and then during the rest of the request the decoded authenticated user
is accessible via static lookup methods. Special steps have to be
taken in rare multi-threaded situations but patterns for that are well
established.

I prefer the security layer be something that is independent of the
methods themselves. In larger organizations the only thing enforcing
that security was implemented would be dev policies which are harder
to enforce than transport or RPC envelope based auth. Simply having
the token on the method doesn't mean that the method itself is
performing the appropriate checks.

A downside to putting auth tokens in the RPC envelope (or the method
signature for that matter) is an increased attack surface for man-in-
the-middle attacks. Packet sniffers would be able to steal the tokens
and reuse them quite easily. The use of encrypted transport (e.g.
HTTPS) for *every* request is a performance drain that isn't practical
for most applications, especially those built to scale.

Cookies are also subject to some of this but much work has been put
into that area, and it is at least well enforced by browsers. Plus
then the security model is the same for both JSON-RPC requests as well
as other communication channels (e.g. page requests in the web world).

Matt (MPCM)

unread,
Oct 30, 2008, 1:50:54 PM10/30/08
to JSON-RPC
> and reuse them quite easily.  The use of encrypted transport (e.g.
> HTTPS) for *every* request is a performance drain that isn't practical
> for most applications, especially those built to scale.

I guess it depends on how you 'scale' or need to 'scale'. All of my
json-rpc apps in production are only over https (by security
requirement).

--
Matt (MPCM)
Reply all
Reply to author
Forward
0 new messages