Using openid-connect for authentication spa and rest api
Asked Answered
F

1

8

I have an API Server (Resource server) and multiple apps, Web GUI (SPA) and a Desktop client and maybe more coming. I'd like to use openid-connect besides http basic authentication for my API Server. It should be configurable which openid provider to use. My own, facebook, google... I only want to do authentication, I do not need their API. I only need some profile data like email or firstname.

Let's say I have configured google as my IdP and I'm currently using my Web GUI (SPA). I need to login, no problem, according to https://developers.google.com/identity/protocols/OpenIDConnect I redirect the user to google, get my authorization code and the Web Gui (SPA) gets an id_token and access_token from google.

No problem so far, but now the SPA has to work with my API Server and the API Server needs to authenticate every request (since it is a stateless rest api) coming from the Client (WebGui SPA) and needs to know which user actually did this.

A

So the access_token from google is meant to be used to access google api's right? But I also could just pass this access_token with every request to my api server and the api server calls https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=xxx to verify the access_token and get the account name (mail). But this doesn't sound right, does it?

B

I also have and id_token which I can verify without calling google server everytime. So could I also just pass the id_token as bearer with every request to my api server and the api server can verify the id_token? But according to openid-connect spec the access_token is actually the one which just get passed to the api server and the id_token must stay on the client. But then the id_token would be completely useless to me, the API server needs to know who the user is, the client (Web GUI) doesn't really care.

C

Or since it is my own API Server, does my API Server actually needs to implement the whole oauth2 system by itself, just not authentication but creating access_token and more. So I would have a /api/tokensign to which I can pass the id_token from google, the API verifies the id_token and creates an access_token for my WebGUI (SPA). And this new access_token can be passed as bearer to every api request. This actually sounds as the best solution according to specs, but do I really need to implement oauth2 by myself into my API? Sounds like a heavy addition since A and B could also be implemented.

My rest-api needs authentication with every request so is A, B, C the right approach? Please don't tell me this is opinion based, it is not. What is the right way using oauth2/openid-connect for authentication?

Felly answered 21/7, 2017 at 16:9 Comment(0)
Q
2

You can use all three methods you have mentioned above, but indeed with some considerations. I will explain them with regards to available specifications.

Scenario - Two systems S1, S2

  • S1 - Identity provider
  • S2 - API endpoint

What you need - Trust and use 'Tokens' issued by S1 to access S2

Explanations for proposed solutioins A, B and C

A - Verify tokens issued by S1 for each call

This can be done using the RFC7662 - OAuth 2.0 Token Introspection endpoint. This validation is valid by the specification so yes you can use the token verification endpoint.

Advantage for this method is that, if a token is revoked, the effect is instantaneous. The very next API call will fail. But indeed there's the implication on performance. You need an extra verification service call.

Note that you do not need to get the account name from this verification response. It could be taken from ID token and could be used to verify for extra protection.

B - Trust tokens issued by S1 for each call

Now this approach is something extended from RFC6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage. You can indeed use ID toke to authenticate and authorise an end user. This link contains a good explanation on the ID token usage as a bearer token.

You can indeed verify the validity of token using MAC and even encryption. But be mindful to use short lived tokens and to always use TLS. And be mindful about refreshing tokens.! Because according to openID connect specification, ID token is not a mandatory item for a refresh token request.

C - A wrapper for federation

For this you can write your own solution or use an existing solutions (ex:- WSO2 identity server). This identity server will configured to choose the identity provider on your application (client like desktop app or web app). Identity server will do the necessary redirects and provide you the required tokens. But indeed you will need to use introspection endpoint to validate the token validity.

If you go one step ahead of this solution, you can try to implement a code exchange mechanism. You can exchange the token carry from external to tokens issued internally by one of your system (ex:- Google access token to your internal access token). The advantage of this approach is you have control over validation. Also since subsequent token validations are done internally, there should be a performance improvement.

Hope this explains some doubts you have.

Quodlibet answered 22/7, 2017 at 4:55 Comment(10)
thanks @KcDoD, I guess B wont solve my problem since yes the id_token is not renewable (it could be done via prompt=none but it is an authentication request every time the id_expired) and still according to specs not meant to be sent to a resource server. So if I have a desktop app the app needs to renew access tokens which can only be done with refresh tokens.Felly
So it will be either A or C. A is fairly simple to implement wheras C is quite complex because I need to implement all those oauth flows I want, idp id_token exchange, probably I also need to register clients and more. I do not want any third party product. the whole server is opensource and it needs to be portable. One major advantage compared with A is that somebody can run the server and the api can throw out access token even this particular person does not want to use any openid provider....Felly
So if the desktop app is a 1st party app and no idp is used the user can obtain access tokens via the resource owner flow by exchangin user/pw. This does sound more secure than just using http basic auth if no openidp connect provider should be used, doesnt it?Felly
@Felly yes, solution B have the problem of refreshing. And solution B and solution C can be combined too (exchanging internal tokens for issued ID token), but indeed with some development overhead.Quodlibet
Be mindful, resource owner credential flow is intended to be used when neither of the available flows are applicable. Basically it's to convert legacy systems to OAuth2.0. It is not more secure than basic auth.[tools.ietf.org/html/rfc6749#section-4.3]Quodlibet
If you want to use openID connect and if you can use introspection to validate the tokens, I recommend to go ahead with solution A.Quodlibet
thanks @KcDoD, I'm going to accept this as answer since all 3 ways could be a possible solution. I have a follow up question regarding this case but with a desktop app (#45264713)Felly
but compared with basic authentication I do have some advantages, for example grant is not revoked if the user changes his password. Or I don't need to store the user credentials especially if we're talking about a desktop app. But since the server is opensource and the client as well the client and server would be required to ship with client_secret/id in source code which is probably not ideal, so maybe I stick with basic auth and if configured additonally an openid connect IdP. I'm talking about a SPA web gui and a desktop app.Felly
@KcDoD I agree that the id token is not suited for the intended usage described in B. But since the access token has no explicit format (according to oauth 2.0 specs), it could be a JWT too. Therefore one could use the the access token and verify it as described in B. Or am I missing something?Squally
@Squally If the ID token can be verified (using MAC, expiration time, audience and other checks defined by openid connect), one can make use of it for intended usage. And yes, access token can be a JWT or simply a gibberish. It depends on the authentication server (AS) implementation. One way to verify an access token is to use introspection endpoint as described in A. But if access token is gibberish, usually that need to be used for a service protected by AS.Quodlibet

© 2022 - 2024 — McMap. All rights reserved.