We have a single API X which needs to be available both internally and externally to the company. Is it possible to allow basic authentication to X using only a Client Id for internal consumers but require oAuth authentication to X using a Client Id and Auth Token for external consumers? Preferrably, with client id and oAuth fields all passed in the http header to both APIs?
We currently have a single product containing two APIs (API X and an oAuth 2.0 provider API scoped to API X). We have added two security definitions to API X, Option 1 is oAuth and Client Id. Option 2 is Basic (Client Id only). For oAuth, we are using a confidential, application flow scheme where app sends client id and secret to oAuth provider API, and gets back an auth token and then passes the (same) client id and auth token to API X.
OAuth access to API X is working fine using http headers, but Basic access to API X only works if we pass client id in the Query string. We'd prefer to always only use http headers.
I'm still very open to a better answer but We have found a workaround.
We removed the Basic authentication security definition from API X so that it only has the oAuth 2.0 security definition. We then created a new API Y which is identical to API X except that it only has the Basic authentication security definition. It has the same base path and paths as API X. We created a second Product and added API Y to it. Just to recap, Product 1 contains API X and its oAuth API. We subscribed the internal consumers to Product 2 and external to Product 1 and we have success. Authorization is completely handled within the headers.
Surely there is a better way?
Related
We have an application that has frontend UI(Which is a web application) which communicates with a resource server. Our frontend will be using some APIs from a resource server to get data.
I am planning to add frontend to Okta and provide access to okta registered users.
In the resource server, we have some APIs that we want to expose to our customers to integrate in their system(Programmatically). To use our APIs, we have to provide client credentials(client ID/secret) to them. Using clientId/Secret, they will get access_token and will use that in a subsequent request. We can display this clientId/Secret via frontend UI once the user logs in to it via Okta.
How should I authenticate requests to the resource server from the frontend? And how do I authenticate requests to resource server via customer using clientId/Secret? Should I use one or two different tokens for this purpose?
Does Okta provides per-user client Id/secret that user(customer) can use to get access_token and send it to access resource server and resource server validate token against Okta.
I just did something very similar. You can read about my experience here: How to pass/verify Open ID token between .net core web app and web api?
I don't know what application framework you are using (.net, node, etc), but if you're using .NET the steps are to (a) install the middleware in your web app, (b) install the middleware in your api app, and (c) make sure calls from your web app to the api app pass the id_token.
If you, in addition to that, need to secure it for external users - it should work the same way. The only difference is they will manually call the /authorize endpoint to get their token - but the middleware should take care of the token verification for you in both cases.
Note I did experience one odd thing which is that I needed to pass the id_token and not the access_token. It is also worth mentioning that the claims were interpreted differently in the app and the api (in that the name of the claims for say, userid, were different between them - the data was still the same).
You will have to use 2 different access tokens. There are 2 different flows going on here:
Web UI to API
Business partner system to API
Technically this means:
Authorization Code Flow (PKCE)
Client Credentials Flow
And in terms of tokens it means:
In the first case there is an end user represented in access tokens (the 'sub' claim)
In the second case there is only a Client Id claim in access tokens
I can advise on token validation techniques if needed - let me know.
To me though this feels like an architectural question - in particular around applying authorization after identifying the caller and versioning / upgrades.
Based on my experience I tend to prefer the following architecture these days, based on 2 levels of APIs: eg with these ones exposed to the internet:
User Experience API serves the UI
Partner API deals with B2B
And both entry point APIs call the same core services which are internal. Might be worth discussing with your stakeholders ..
I'm integrating several web sites/services into my application. I use iframes (or webview for Vue Electron) for UI integration and I also use API to implement cross-communication between those services.
At the moment I have to go through OAuth 2 authentication twice for each service: once as part of natural authentication in iframe and another when I ask the user to give me access to this service (for api reasons).
Is there any way to streamline this process?
The state of the art response would be to modify your application completely.
You should have 1 SPA application and not iframe
This application would authenticate to get OAuth2 token
This application would then call the backend (access multiple backend, or access on api management layer that call backends).
Thing is, with this you can have 2 strategies :
give all permission (scope) at 1st authentication
give the smalled scope possible at 1st authentication, then when needed "reauthenticate" (in fact validate new scope) to get new access token
When an API want to call another API, you have also 3 strategies:
you simply use the same client token the API receive to the service your API call (no human interaction needed)
your API generate a token from a service account (using ROPC authentication scheme) or via a client credential scheme (the access token will be valid but usually not be bind to a real user), (no human interaction needed). (the API will be the client of the 2nd API)
your identity provider have an endpoint to transform access token : Your API can give the client access token, and authorization server will transform this with the client_id of your API. You send this token to 2ndAPI ( token will show subject of your UI application, but client ID will be the 1st API clientId) (no human interaction needed)
Now if you use IFrame with multiple sub-application on the same domain (the domain need to be exactly the same!), it is possible to share the same access token for instance via local storage. (security is not top notch)
You will probably need to authenticate with a bigger scope list sometime but it is your only option. You will simulate a single page application, but issue is that you will have potentially different client_id depending first application you authenticate to.
Edit: Multiple authorization server
From your comment, you have multiple authorization server. One strategy could be to ask user to authenticate, your application can then get an access_token and a refresh_token.
Depending on your authorization server, refresh_token can be used a lot / on a long period of time, so that if you store it somewhere, the next time the user visit your application, your application can silently get an access_token from this refresh token. Your application have then access to remove api without newer interaction from your user.
Of course, this means you have to save this token the most safely you can.
By using OpenID Connect you could combine authentication and authorization in a one step and get both an id_token to logon your user to your app as well as an access_token to access APIs in a single authentication response.
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?
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.
How / can I get Google cross-client auth to work in a client-type-agnostic way (e.g., using only a web browser and cURL commands)?
I have two OAuth 2.0 clients (let's call them Client A and Client B), both of type "Web Application" and in the same Google API Console project. Each client's credentials is used by a different app (say, Apps A & B, respectively):
App A implements Google Sign-In using Client A; the ID token obtained after a user signs in is sent to a /verify endpoint, which verifies the token and authenticates the user to the app.
App B wants to automate the offline authentication of a specific user to App A by sending an ID token (obtained using Client B's credentials) directly to its /verify endpoint. (Note that App B doesn't have access to Client A's secret.) The general strategy is:
manually get a one-time-use auth code for the user (using proper scopes and access_type=offline),
exchange it for tokens (requires client secret),
securely store the refresh token and use it to generate ID tokens whenever I want, which I'll in turn use to authenticate the user to App A.
If App B uses tokens obtained in the "normal" way using Client B credentials, then App A will see my ID token as invalid, since the standard check involves verifying that the decoded token's payload has an aud value equal to Client A's ID, which it won't.
Cross-client identity/auth to the rescue, right?
From https://developers.google.com/identity/protocols/CrossClientAuth:
Google considers that when a user has granted access to a particular scope to any client ID in a project, the grant indicates the user's trust in the whole application for that scope.
The effect is that the user should not be prompted to approve access to any resource more than once for the same logical application, whenever the components of the application can be reliably authenticated by Google's authorization infrastructure, which today includes web clients, JavaScript clients, and Android apps.
(Emphasis mine.)
The Problem
The problem is that, while the docs explicitly say that what I want to do is possible, it only shows an example for Android -> Web cross-client auth, which involves calling a specific utility function available only on Android, passing the scope as a "magic string" of the form oauth2:server:client_id:{CLIENT_A_ID}:api_scope:{SCOPE1 SCOPE2 ...}.
I've scoured the internet and have found zero examples of how to do this in a generic way or for other client combinations. I've tried naively sending a similarly-constructed "magic" scope string when requesting an auth code, which is seen as an invalid by Google's servers (invalid_scope 400 error). I've stopped just short of decompiling Google libraries to see how it translates this string into actual server requests (if that's, in fact, what it's doing).
My question: Does anyone know how to get Google cross-client auth to work in a client-type-agnostic way? (Or at least in the specific way I'm asking?)
I have an API that requires authentication via OAuth 2.0. I originally anticipated using HWIOAuthBundle, however from investigation this is more to do with hooking up 3rd parties into Symfony's security/auth mechanism and does not provide the required mechanism for validating OAuth 2.0 Authorization headers.
I then found some information about FOSOAuthServerBundle which enables an application to become it's own OAuth 2.0 provider as well as providing the required security mechanisms to validate Authorization headers.
However the problem is that I would like integrate the OAuth 2.0 provider (authorisation server) in an external application (which contains the user base) and not include it within the API. Which will provide some mechanism for performing the token verification against this external app via (another) RESTful API.
Points:
RESTful API requires OAuth 2.0 authentication.
OAuth 2.0 authorisation server to be situated in a separate application.
I feel I should use Implicit grant and call the authorization server on each request to validate that the token is correct.
Is my thinking correct?
As far as I undesratnd your requirement, you require to authenticate your APIs via external OAuth Authorization Server:
Client needs to provide the access token retrieved in the above steps
along with the request to access the protected resource. Access token
will be sent as an authorization parameter in the request header.
Server will authenticate the request based on the token.
If token is valid then client will get an access to protected resource otherwise access is denied.
here is an example which might help you to achieve your requirement. Check this document .
Or simply, you can do with Jersey and Oauth
Also, you can check Apache Oltu and figure out the way to achieve your requirement.
A lot of the big companies like Google, Facebook etc have a separate authorization server from the API server. Check out Google's OAuth authorization flow below
You can also check Google's OAuth Documentation for the details.
So all you would need to do is implement a OAuth Provider so that you can authorize against that provider. There's a list of libraries available on the OAuth website: http://oauth.net/code. You can specifically look here; there is an example for running an OAuth Service Provider in Java.
oAuth can most definitely be a server other than your application server. Below is a picture of what the authentication sequence would look like:
-- Obviously, if the forum can't decode or validate the token, the forum would return a 401 status code instead of a 200 status code.
As long as your oAuth server & the Forum share the same public key, you're more than okay with splitting your oAuth Server & your application.
In fact, take a look at jwt.io. Paste the token you get from the oAuth server into there. It should be able to decode the token right away. Then, you can put your public key into the 'secret' text box to verify the token is verified.
Your application (Forum, in this example) should be able to do the same:
1) Grab the token from the Authorization header of the request
2) Decode the token
3) Check the expire date
4) Verify the token using the oAuth's public key
5) Return successful status code or a failure status code