I am building an application that spans over several parts of infrastructure.
An end-user can sign in to a portal using OAuth 2.0 authorization code flow. When calling different APIs, the portal requests tokens on-behalf-of the signed in user and attaches those to outgoing requests. The tokens received to call external APIs have an aud claim matching the target API.
When a call to an external API is fired, it first passes through an API Gateway. This API Gateway validates the token and ensures the aud claim is actually intended for this endpoint. It also verifies roles and a few other claims.
When the gateway checks pass, the request is forwarded to the actual implementation. Now the actual implementation also verifies the token, but only that the token is valid (e.g. not looking at specific claims). That is not to say that the claims aren't used internally in the application after the token is validated, roles are very much part of the application logic.
So to summarize this as bullet points:
User signs in to portal
User performs some action that causes an API call
Portal attaches token to outgoing request
Request hits gateway for 1..n claims are validated
Request is forwarded to actual implementation
Implementation again validates token is valid, not looking at claims
All endpoints are public, e.g. I could call any of these from anywhere as long as I have a token.
In the above outlined scenario, I'm handling the token properly?
In general, what is the recommendation for tokens passing through several layers of an application? Should every layer validate the token? If yes, are there exceptions to the rule?
Typically, JWT tokens are validated when are sent from the client-side to the server-side. As these tokens are signed, if anyone tries to tamper with the token before sending it to the server-side endpoint, the token verification will fail, therefore these tokens are a secure way of sending the session of an authenticated user to an API or a server endpoint.
These JWTs can be also transferred between servers or different application layers, and it always would be a good practice to verify the token before processing it. It is adding a layer of security to avoid anyone sending tokens to that layer directly and skipping the validation.
Related
When a user logs out (sign out) of the application, how does the gateway communicate to all services that the user has logged out?
In other words, what happens when a user logs out in microservice architecture application?
This is generic question, I will give my personal thoughts.
Let's take a Single page application, talking to bunch of Microservices and secured by a Gateway that validates the token.
When user logs in, token given by auth server is stored within browser storage(ex: localstorage).
When user log out, no communication is sent to Gateway or auth server, tokens will simply be deleted from browser storage.
So, if someone gets hold of access tokens, they can be used to call services as long as access tokens doesn't expire.
This is typically why there are two tokens given by auth server, an access token and a refresh token. Access token which is used to secure apis expires pretty quickly and a refresh token which has much longer expiry time can be used to get new access token.
As you've included the JWT tag, so I'm trying to give the response by considering that only. The JWT token is a self-sufficient encoded token that contained certain attributes including an expiration period. The sole purpose is to provide stateless authentication. Authentication service usually returns two token, access_token and refresh_token. Client store both of them in some storage on their end. Access token usually issued for a very short span of time and so the client can use the refresh_token in order to get a new access_token on the expiration of the latter. One can access the services until refresh_token get expired. After that client has to go through the authentication process to get new tokens. In case when user logout from the system client should remove both of the tokens from its storage. Because as there is no state maintain in the case of JWT, the server can still accept the old token until they're not expired.
Validation of token for expiration and integrity should be done at the gateway level.
One can avoid the use of the token for service to service communications as those are internal services and running in a private network although one can do the same validation at this level too.
So in case of user sign out, the user's auth token should be removed from the client-side and the gateway should not communicate to other services. There are other special cases where token revoke is a particular case that could be handled by taking the help of distributed cached store in scaleable authentication systems.
A token-based service can generally infer the following from a token -
Who made a request?
Upto what time this token is considered valid?
Which actions are allowed when using this token?
A token based service just accepts or rejects a request depending on provided token, regardless of whether it is a user or a machine making the request. A logged-in user is just someone who can perform actions which this user is authorized to do. A token is a limited representation of such a user.
My point being, it is the application telling the user that they are logged in (have a token it can still use), or logged out (no token yet, or expired). Such a token is obtained by authenticating to the service using ones username and password.
Answer is based on my knowledge, so everyone, please do point out mistakes if any. I don't know in detail about aws api gateway stuff, so maybe someone else can brief you on it in case it works differently.
I have 3 services (in the real much more):
Authorization service (uses OAuth 2.0)
Frontend service
Resource service
and client (web-browser).
I store session_id, access_token and refersh_token in cookies of the user's web-browser. The user goes to Auth service, signs in and gets these tokens. After his web-browser is redirected to Frontend.
Frontend and Resource services can't validate tokens because they know a nothing about it, so they must make a request to Auth service.
The current scenarios:
The user (web-browser) sends a request to Frontend service, the Frontend sends a request to Auth service to validate access_token. If it's invalid the Frontend sends a request to refresh token using refresh_token.
If the Frontend needs an access to Resource service to process a request then the Frontend sends its client_id and access_token to Resource service. The Resource service sends a request to the Auth service to validate an access_token too.
Are my thoughts right? Or it has simpler schema?
P.S. All services use RESTful architecture.
OAuth talks about how the tokens be exchanged. What you have mentioned it seem liek you are talking about using implicit grant, which is little less secure and you may think of opting for authorisation flow.
Other than that, in microservices when you have many services and one user request pass through many downstream services, verifying the token with auth provider at each and every step might become a bottleneck.
There are ways out there by which you can skip this call to auth server and still validate the sanctity of the token without making an explicit call.
One way is to make use of JWT. These tokens are signed by the Auth provider and your services have keys which can help you validate if the token is modified on it way, and token itself has all the information you need to ensure validity of it, like expiry time, intended audience, clients, roles etc.
On login you get AT and RT. AT could be passed along to downstream for authentication and authorization and RT could be used when AT is expired.
You only need to talk to auth provider at the time of login and when you need to refresh the token.
You can read more about the JWT OAuth2.0 with JWT and OIDC to get more information around it
A common situation: SPA + REST. If one were to forego Auth0 and authenticate the web users with JWT's, one would have to store an XSRF token provided by the server on login in a cookie, and send it in the request headers, along with the JWT.
In the relevant official Auth0 guide, https://auth0.com/docs/architecture-scenarios/spa-api, the XSRF tokens are not mentioned at all. What if someone steals the Access Token from a user? Will they have access to my REST API for that user?
Auth0 has another guide Preventing Cross-site Request Forgery (XSRF or CSRF), but it's strangely brief, and I'm not seeing how it solves the problem I described.
the strategy Auth0 uses to prevent CSRF attacks is by the use of a nonce, which they call a state parameter. This state is generated with the authentication request, and then used to correlate the request with the response received from the authentication. (from Auth0 docs on how to mitigate CSRF attacks)
Relevant info from the Auth0 docs on the state parameter:
a unique and non-guessable value associated with each authentication request about to be initiated. It’s that unique and non-guessable value that allows you to prevent the attack by confirming if the value coming from the response matches the one you expect (the one you generated when initiating the request).
If you are using Auth0.js in your SPA this nonces or state generation and validation is automatically handled for you.
When you authenticate with an OIDC provider you get back an id token and if you specified scopes for an API you get back an access token so that client applications can make requests to protected resources on the end user's behalf. Typically the access token is also a JWT.
But what is to stop someone from spoofing one of these access tokens, and creating one and passing it to an API? I understand there are safeguards to prevent modification because the signature will be different than what any validation logic is expecting, but what if a malicious user created a brand new one manually? Especially because these tokens can be validated 'in place' by any API that requires an access token (not all API's use the introspection endpoint... especially with a JWT). I do understand there is metadata around the signing keys for JWT's from OpenID Connect providers and that it is available in the OIDC discovery document. For example, here is Google's JWK metadata. Given that you have signing information publicly available, and JWT access token's can be validated without any requests to the OIDC provider, how are JWT's secure? What is preventing a person from creating one and passing it as a bearer token to an API that requires an access token?
But what is to stop someone from spoofing one of these access tokens, and creating one and passing it to an API?
Spoofing and reconstruction of signature is nearly impossible without the private key (assuming you are using asymmetric signing algorithm like RS256) that used for signing the original JWT.
The JWK information available via OIDC discovery document only contains the public key.
Also Use HTTPS for authorization / token exchange to avoid token sniffing.
I am new to building API's and I am having trouble understanding how to perform the following task reasonably.
There is an endpoint:
/user/{user_id}
which retrieves the details of the user.
The frontend code will request this endpoint to get details about the user to display on the dashboard.
I have to protect this endpoint so that a user who doesn't represent this user_id, emulates the request to get information about other users.
Since REST based API's are sessionless, I cannot store session keys. So how do I make sure that the server sends the user information only if the owner of the user id has requested it?
You are right. HTTP is a stateless protocol, therefore REST inherits that quality too.
Here is the deal in simple words.
[REST client] -------> [API endpoint]
You have many REST clients, and you need to make sure that only authorized users will grant the access to your API endpoint. One solution as #James suggested is use a token mechanism such as JWT https://www.rfc-editor.org/rfc/rfc7519.
If you consider JWT authentication, the process flow will be as follows.
[REST client] -------> [AA service]-------> [API endpoint]
You will need an AA(Authorization, Authentication) service in the middle. For example in a microservices approach, this can be performed from a API gateway which is a gateway to all of your services.
Client will give AA service their username and password. In exchange AA service will give the client a JSON token signed only by the server so that the confidentiality is protected. This token contains 3 things.
Header which specifies the type of token and algorithms used to sign it
Payload which includes claims like to whom the token is issued, when should the token expire, what is issued user's role should be etc. (see https://www.rfc-editor.org/rfc/rfc7519#section-4)
Signature which a product of unsigned token signed by the server key
Then you encode each header, payload, signature with base64 and concatanate with a ".". You now have a JWT.
AA service returns this JWT in exchange for credentials.
Client should store this token securely (ex: local storage) and the communication medium should be encrypted(ex: TLS). See https://stormpath.com/blog/jwt-the-right-way#how-to-secure-jwt , https://www.rfc-editor.org/rfc/rfc7519#section-6
After that for every subsequent REST call, client should include the received token, preferably in the Authorization header although it is technically possible to send the token in the message payload as well.
Then it is AA service's responsibility to decrypt the token using its signing key evaluate claims in the JWT and act upon whether to authorize the API call send him HTTP 401,403 responses.