Background
Say I have an application to create shipments. A user sits down in front of that application and loads the page. They are then redirected to the IDP to login. The flow I use is the Authorization Code flow. This involves a Client ID and Client Secret. The IDP can take those values along with the User's Credentials and do the login.
After the login, the application gets an id_token that lets the application know who the user is (authentication).
The application then needs to call a service (we can call it Service 1). The application can pass the id_token to Service 1 as a JWT bearer token.
Service 1 gets the JWT and can use the signature on it (with the IDP's public key) to verify that the JWT in fact came from an IDP that it trusts.
Problem
This is all great and works just fine. But now Service 1 needs to call Service 2 to fulfill the Shipment Application's request.
This is where things get confusing for me. Service 1 has its own Client ID and Client Secret. And it can get a "Client Credentials" token. But Service 2 needs to know the user that is making the request and a Client Credentials token does not have any user information in it.
The Authorization: Bearer header only allows for one token. But I need space for two:
If I only pass the User's JWT, my JWT looks like the call came directly from the Shipment Application to service 2. (It may be that Service 2 should not even be called directly from the Shipment Application.)
But if I pass only the Client Credentials token of Service 1, then Service 2 is not going to get the user's information.
Either way Service 2 is not going to be happy.
Question
Does OpenID Connect have a way to merge two tokens? Or some other way to allow for chains of service calls to work?
NOTE: I currently am passing both. One in the Authorization: Bearer header and one in a custom header. But because this is not part of the OpenID Connect protocol, it is causing issues when working with 3rd party tools (like OpenAPI (aka Swagger)).
You can look at delegated tokens pattern to issue a new token for Service1 to Service communication.
See:
https://auth0.com/docs/tokens/delegation-tokens
https://www.scottbrady91.com/OAuth/Delegation-Patterns-for-OAuth-20
Related
I'm trying to use Azure AD to lock down access to authenticated users. I'm hoping someone could direct me to a setup that might fit the need here (and I feel like I must be overlooking the solution...).
We have an application that will expose various endpoints to be called by other teams in the organization. Nearly all of the consumers will be other user-less applications. (also none of these are Azure hosted/deployed services)
For auditing purposes, one of the requirements is the need to know what user (service) is calling any given endpoint.
Essentially, in the following:
We would need to be able to have Consumer 1 call My API, Consumer 2 call My API , and be able to determine inside of My API who the current consumer is.
I know with the client credentials flow, we could create multiple secrets and provide one to each consumer. However from the generated token, it appears that these are essentially both tokens on behalf of the Service Principal (so no way to know who the call is coming from).
I'd also looked into the ROPC flow, but I think am running into issue since we are using ADFS with our on prem AD servers.
Any easy button I'm overlooking? (fingerscrossed)
Please allow me to share my humble opinions here.
Firstly, access token is used for calling api which contains the information that if the token has correct scoped for the target api. And Id token contains the user informaion.
So if the Consumer1 and Consumer2 are on behalf of application itself, then it can't add user information within the access token and there's no id token for it. In this scenario, I think what you can do is adding an identifier into the request along with the access token, then your api application can both check if the token is illegal and which Consumer sends this request. This scenario used client credential flow to generate access token.
If the Consumer1 and Consumer2 are on behalf of users, or they are application but the request calling your api application can get the current user information, then you may send id token along with access token, or just send the user id as an identifier. This scenario may need users to sign in, so maybe auth code flow is better then credential flow.
I have a web app MyWebApp.
And two APIs: MyAuthAPI and MyServiceAPI, both RESTful NodeJS. MyAuthAPI uses HashiCorp Vault as a token store with OAuth2.
MyServiceAPI has CRUD operations available to authenticated clients.
There is no human login required (or desired) on MyWebApp. Any human can access MyWebApp through a browser and run the service.
At present, this is the (very insecure) flow:
MyWebApp sends clientid and clientsecret to MyAuthAPI to retrieve token. This token is then used for communicating with MyServiceAPI.
The obvious downside is that anyone can capture the clientid and clientsecret by simply looking in developer tools in a web browser. They could then use those to authenticate with MyAuthAPI, generate their own token, and make calls to MyServiceAPI without MyWebApp being involved.
So how do I best secure the entire application so that MyWebApp is safely and robustly authenticated without revealing the credentials?
Thanks.
ETA:
I want to be able to authenticate MyWebApp with MyAuthAPI and then use the generated token to connect to MyServiceAPI. But I don't want it to be possible that anyone can intercept those credentials - currently they can be see in the request header as "Authorization: Basic "
The MyServiceAPI endpoints must be secured so that only authenticated clients are able to access them. But when that client (MyWebApp) is a public website, how do I authenticate without making the credentials visible?
ETA2:
https://mywebapp.com is MyWebApp which is a React application.
https://myauthapi.com hosts MyAuthAPI
https://myserviceapi.com hosts MyServiceAPI
When I load mywebapp.com in a web browser, it authenticates with myauthapi.com/oauth/token to get a token. At present it does this by sending the creds in the header Authorization: Basic
The token that is returned is then saved.
The web application then tries to get the data from an endpoint on MyServiceApi using this token:
Authorization: Bearer
GET https://myserviceapi.com/objects
or POST myserviceapi.com/objects
or GET myserviceapi.com/objects/objectid
or DELETE myserviceapi.com/objects/objectid
MyServiceAPI verifies the token with MyAuthAPI, but that isn't public-facing, so there's no issue there.
The issue is that, as you can see from the attached screenshot of the Developer Tools console in Chrome, anyone using the web application can see the Authorization header containing the credentials, and could then use these credentials to programatically gain access to the auth API to generate a token which can then be used on the service API endpoints.
I want to restrict all access to the API servers to only come from specific applications, such as MyWebApp, on mywebapp.com.
First, I think this question could better be asked in https://softwareengineering.stackexchange.com/.
Second, where MyWebApp is deployed? How it is being used? If it works with https, then the body is encrypted, and when you send the clientId and clientSecret, you should send it in the body, so users will not be able to see them.
Client Credentials Grant should only be used by confidential Clients. Thats because you can't hide the client_secret on non confidential Clients. Your frontend seems to be a non confidential Client.
Normally you should use the Authorization Code Grant with PKCE. But you would need users to authenticate themselves for that.
Feels like you need an architecture design based on standard flows, since OAuth should work like this:
Web app signs user in via an Authorization Server, using Authorization Code Flow (PKCE)
Web app gets tokens from the Authorization Server
Web app calls API with an access token
API validates token using data from the Authorization Server
API then trusts claims in the access token and uses them for authorization
See my Initial HTTP Messages blog post for an example of how this looks.
Assuming you have an existing user management/database on a web platform. Sign in with Apple should be integrated for a quicker login and registration process – although it will always create a regular account linked to an email address (just without a regular password). Is it safe to use the (validated) JWT provided by Apple for authenticating?
Signing in (existing account) would be the following steps:
User taps on "Sign in with Apple" in an app
the generated JWT from Apple is sent to the authentication server
the server validates the JWT using the public keys provided by Apple's API endpoint
the server extracts the email from the (validated) JWT and if a user with that email exists, this user is signed in (API returns internal access/refresh token for the session)
I try to craft an answer for iOS apps. But first clarify the question:
"Is it safe to use the (validated) JWT provided by Apple for authenticating?"
The only known JWT we receive from an Authorization task is the "id_token". Other parameters may be JWTs as well, but these are opaque for the client.
The question is now, if we send the id_token to the app server, is it sufficient to just validate the id_token to hand out the client an access token for the app server's domain? Answer: NO!
When using Apple's Authentication Framework for iOS for Sign in With Apple, the Authorization task returns an ASAuthorization value in the completion handler. This contains basically the following parameters:
user: an identifier
identityToken: JWT the "id_token" (see OIDC)
authorizationCode: A short-lived, one-time valid token that provides proof of authorization to the server component of the app. The authorization code is bound to the specific transaction using the state attribute passed in the authorization request. The server component of the app can validate the code using Apple’s identity service endpoint provided for this purpose. *)
*) If that value does correspond to the OIDC "code" value which will be obtained by a client via the "front channel" aka user agent aka browser, then we should also ensure that an additional mechanism is in place which actually provides a secure "proof of authorization" (Universal Links, PKCE), see Authorization Code Interception Attack.
If these attacks are technically impossible, because the authentication system provides secure communication channels with the app, we don't need PKCE, though.
The id_token contains information about the user that has been authenticated which is stored on the Provider. It's a signed JWT. Even if the JWT can be successfully validated, with the JWT alone the app server cannot be sure that the sender is the one who it believes it is. We don't want to give anyone an access token who is not authenticated!
The app server needs more prove and this will be accomplished with the authorizationCode parameter. This check has to be done on the Provider though.
So, we have to perform two steps:
Verify the Identity Token (id_token)
This will be performed on the app server.
Validate Authorization Code
The second step will be accomplished by your app server obtaining a refresh token form the Providers special endpoints.
With Step 2 we receive a TokenResponse.
If this was successful, we receive an access token and a refresh token. The access token is of no use, but we need the refresh token:
"You may verify the refresh token up to once a day to confirm that the user’s Apple ID on that device is still in good standing with Apple’s servers."
Store this on your app server.
Once after this is all done on your app server you proceed with:
Manage the User Session
After verifying the identity token, your app is responsible for managing the user session. You may tie the session’s lifetime to successful getCredentialState(forUserID:completion:) calls on Apple devices. This is a local, inexpensive, nonnetwork call and is enabled by the Apple ID system that keeps the Apple ID state on a device in sync with Apple servers.
A "User Session" will likely require a domain specific access token and refresh token. You will likely verify again Apple's refresh token when the client requires a new access token on your token endpoint.
So, the last step is your app sending the domain specific access token and refresh token to your client.
Let's say you are developing a client side JavaScript SPA app (Angular), a backend API for this app (ASP.NET Core in my case) and you use an identity provider that implements Open ID Connect protocol (I'm using IdentityServer4).
Apparently the recommended way for securing the app is to use the OIDC implicit flow between the JavaScript app and the identity provider and if successful the JavaScript app gets an id token and an access token.
Now according to this documentation the JavaScript app is supposed to pass the access token in the headers whenever it calls the API. And I'm not sure what purpose does the id token serve in this case (besides customizing the UI in your JavaScript app)?
But this is the confusing part: The documentation also says you should never use the access token for authentication. But that is the token that my API receives in the request headers, how can it authenticate the user then? If my API receives Post(newRecord), and the API needs to internally fix some audit information on newRecord (i.e newRecord.CreatedBy = CurrentUsername), how can it do that without authenticating the caller??
I think I'm missing a piece of the puzzle. Please any help is deeply appreciated.
Short answer/suggestion
Use Access Token to access API endpoints. From API endpoints, you must use token introspection endpoint to validate token validity (active state) as well as obtain subject who authenticated at authorization server. IdentityServer provide support for this. Documentation is available from here.
Explanation
ID token is intended to be used by receiving client. It will allow your client to authenticate the end user and provide user specific customizations. This is the whole purpose of OpenID Connect (OIDC). On the other hand OAuth 2.0 provide an authorization framework. It replaces user credentials with access tokens, thus improving API access security (compared to basic authentication and storing user credentials everywhere). Hence OIDC is built on top of OAuth 2.0, you get both ID Token and Access token with OIDC flow.
But as you have figured out (and mentioned before), ID token is intended for client. There are could be exceptional cases where ID token get passed between client and a server. This is mainly when both are controlled by same party. But the access token is the key to access API endpoints, correctly.
Access tokens can be an opaque string or JWT. When it's a JWT, API can read and understand the token (self-contained). When it's opaque, only way to validate token at API endpoint is to use token introspection endpoint. If API can validate token validity, then it could grant access (authorize) request. Furthermore, if user details (subject) are available (through JWT or as introspection response), then user specific checks can be executed. This further extends to token scope values. But at the end of the day, you are authorizing the API request and not authenticating the user at API endpoint. That's the highlight. Hope things are clear now.!
I am a beginner to OAuth so my question might sound naive. I found this picture online describing how OAuth works.
Let's say the client already did the authorization before, which means we already know which authorization the clients get.
So, for the second time when the client request the authorization, I am not sure why can't we request the authorization from the client and return the protected resources from the server back to the client? So basically we skip steps 2, 3, 4 and 5, and we only keep steps 1 and 6.
What are you looking at there is the "Authorization Code Grant". This means you have an authentication service that is capable of serving back a login form to the user, authenticates them and then issues a grant. This grant is then turned into an access token via another call.
If you want to do application level authentication then use the Client Credential Grant
This means that you have a ClientID and ClientSecret which identify an application, not a user. You issue a request with those and you get back a token you can use to access a protected resource.
An example is here: https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
If you want to use user credentials for authentication then you can use the Resource Owner Password Credential Grant for example.
So, it all depends on what you are looking for.