I try to check JWT Access Tokens in server middleware zone
If JWT token is expired and if resources is only for authorized users then I return 401 code
But if user requests public resources (granted for anonymous users) with JWT token should I return 401 code when token is expired or not?
How do I notify a user that their token is invalid?
Public resources do not require securing, so you should ensure that your server middleware does not run for these requests, and whether or not a valid JWT is sent, you will then return the resource with a 200 status code.
This is usually done by adopting a path convention such as the following. If resources are public you will not care if a hacker accesses them.
/public/docs
/public/news
I have seen people protect public resources in a basic way, eg via a fixed API key, to limit denial of service risks, though I wouldn't usually recommend this. It is worth mentioning since in that case those paths would use a different server middleware.
For secured endpoints, validate the JWT properly and follow Best Practices:
Use a library to verify the signature, expiry, issuer and audience
Return a 401 status if any of these fail
Then move onto business authorization checks using scopes and claims - eg checking a user is allowed to access the actual data requested
If business authorization fails, return a 403 (or 404 - not found for user) status
Related
I'm working on an application using OAuth2.0 for Quickbooks. I'm basing my code on the example provided by intuit. Here I have looked a bit on the "state" parameter of the oauthClient.authorizeUri.
oauthClient = new OAuthClient({
clientId: req.query.json.clientId,
clientSecret: req.query.json.clientSecret,
environment: req.query.json.environment,
redirectUri: req.query.json.redirectUri,
});
OAuthClient;
var authUri = oauthClient.authorizeUri({
scope: [OAuthClient.scopes.Accounting],
state: "userid:1234", //Encoded as a JWT
});
res.send(authUri);
});
I was thinking of encoding an internal user- and projectid in the state through a JWT only for this purpose. I need it for the callback to make sure that I'm connecting the right internal user with the QB token.
I have two questions here:
Is it "safe" to encode an internal userid in the "state" like that? Or is there a better way of doing what I want? I'm working with a distributed service (GCP CloudRun), so it might not be the same instance receiving the callback as the one that created the authUri.
I'm not an expert here, but a read of the spec seems to indicate this should not be a guessable value like user_id would be.
From the spec ( https://datatracker.ietf.org/doc/html/rfc6749#page-26 ):
state
RECOMMENDED. An opaque value used by the client to maintain
state between the request and callback. The authorization
server includes this value when redirecting the user-agent back
to the client. The parameter SHOULD be used for preventing
cross-site request forgery as described in Section 10.12.
and:
10.12. Cross-Site Request Forgery
Cross-site request forgery (CSRF) is an exploit in which an attacker
causes the user-agent of a victim end-user to follow a malicious URI
(e.g., provided to the user-agent as a misleading link, image, or
redirection) to a trusting server (usually established via the
presence of a valid session cookie).
A CSRF attack against the client's redirection URI allows an attacker
to inject its own authorization code or access token, which can
result in the client using an access token associated with the
attacker's protected resources rather than the victim's (e.g., save
the victim's bank account information to a protected resource
controlled by the attacker).
The client MUST implement CSRF protection for its redirection URI.
This is typically accomplished by requiring any request sent to the
redirection URI endpoint to include a value that binds the request to
the user-agent's authenticated state (e.g., a hash of the session
cookie used to authenticate the user-agent). The client SHOULD
utilize the "state" request parameter to deliver this value to the
authorization server when making an authorization request.
Once authorization has been obtained from the end-user, the
authorization server redirects the end-user's user-agent back to the
client with the required binding value contained in the "state"
parameter. The binding value enables the client to verify the
validity of the request by matching the binding value to the
user-agent's authenticated state. The binding value used for CSRF
protection MUST contain a non-guessable value (as described in
Section 10.10), and the user-agent's authenticated state (e.g.,
session cookie, HTML5 local storage) MUST be kept in a location
accessible only to the client and the user-agent (i.e., protected by
same-origin policy).
A CSRF attack against the authorization server's authorization
endpoint can result in an attacker obtaining end-user authorization
for a malicious client without involving or alerting the end-user.
The authorization server MUST implement CSRF protection for its
authorization endpoint and ensure that a malicious client cannot
obtain authorization without the awareness and explicit consent of
the resource owner.
Given that the spec recommends the state parameter be used for CSRF protection, and that the user_id is going to be easily guessable (i.e. the opposite of what you'd want for CSRF protection) it doesn't seem like a good idea to be putting the user_id into the state parameter.
Some other sources seem to confirm this:
https://auth0.com/docs/secure/attack-protection/state-parameters
https://medium.com/keycloak/the-importance-of-the-state-parameter-in-oauth-5419c94bef4c
I have implemented OAuth2 Refresh Token in my project where i have two servers :
- Authentication Server
- Resource Server
Question : Where should i check if my access token has already expired or not ?
Method 1 : Before sending a request to resource server, we check if the access token has been expired or not at the client side only ? If the access token has been expired then we send refresh token to Authentication server to get the new access token and resend the request to resource server with the new access token.
Method 2 : Request goes to resource server and then we get invalid_access in the response & then we sent a request to Authentication server with refresh token to get the new access token & then again send request to resource server with new access token ?
Request you to share your thoughts on the same.
Thanks in advance.
Some good points above - would definitely recommend method 2 - as you've pointed out yourself it is more resilient.
Also the client side code should deal with other possible reasons for 401 responses, such as load balancing flips or changes to token signing keys.
I therefore always write OAuth clients to call APIs like this code snippet, regardless of technology.
I'm trying to set up Pac4j in my back end (BE) application and in order to configure my Angular front end (FE), I need to understand the workflow that it expects in order to configure the back end properly.
I've been reading reams of documentation and trawling through Pac4j source to find how I get the token from the code without exposing the client secret.
So...
I try to log in FE->BE (without auth)
I receive a 401
I take the 'Location' (the Google auth uri) from the 401 and redirect to it, providing a callback uri
I log in to Google
I am redirected back to my callback uri with a code
(What request do I make to BE in order to get a token back? i.e. where is the token URI that doesn't require a client_secret)
I use the retrieved token to access and continue as normal using BE
If you don't want to use client_secret, then you need public client. I'm not sure if public client is supported by Google.
IMHO better approach will be implicit flow in the FE. It will generate access token, which will be used for BE api calls.
I want to add authorization to my project based on this tutorial. I've got the part of retrieving an access token working. But when using the token to access a protected resource API I get a 401 unauthorized error.
The request has an authorization header with scheme Bearer and containing the access token. Like in the tutorial the API is protected with the [Authorize] attribute. During startup I setup Bearer Authentication with
UseOAuthBearerAuthentication(new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions())
It is not clear to me why the request is unauthorized. What can I check to find the cause of this problem?
After trying and checking many things, I noticed the authorization server and the resource server were using a different version of Owin and Owin.Security. After updating the older one, it worked. The tokens must have changed between the 2 versions.
A client credential grant does not return a refresh token (DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest forbids it). But ClientBase.AuthorizeRequest requires it.
Is this a bug in DotNetOpenAuth or am I doing something wrong?
I suppose I can work around by inheriting ClientBase and overriding AuthorizeRequest. Is that the correct thing to do?
Edit: It's not so easy to inherit from ClientBase outside of DotNetOpenAuth because a lot of the stuff you want is internal only. e.g. ErrorUtilities.VerifyProtocol
Edit2: Just read the draft OAuth 2 spec (draft 25) referred to in DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest and I can't find where it disallows refresh tokens for Client credential grant type. Maybe they changed it?
Google returns Refresh Token if you request it. Provide parameter in query string access_type=offline.
In my case I had to amend default Authorization Endpoint URL to: https://accounts.google.com/o/oauth2/auth?access_type=offline
Google Api C# example using DotNetOpenAuth:
private WebServerClient GetClient()
{
return new WebServerClient(
new AuthorizationServerDescription
{
AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth?access_type=offline"),
TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"),
ProtocolVersion = ProtocolVersion.V20,
},
clientIdentifier: this.settings.GoogleApisClientIdentifier,
clientSecret: this.settings.GoogleApisClientSecret
);
}
NOTE from my experience: This works only for the First request.
See Google Documentation.
I'm not sure why you say that ClientBase.AuthorizeRequest requires it. Firstly, there is an overload that only takes an access token, so it doesn't even ask for a refresh token. The overload you may have tried accepts an IAuthorizationState object, which may or may not include a refresh token, and it appears that that method only looks for a refresh token if the access token has expired. Since an expired access token can't be used, it tries to refresh it and throws if it can't. It seems reasonable to me.
Whichever method overload you choose to call, your calling mode must either avoid using expired access tokens or be prepared to respond to the exceptions that are thrown when DotNetOpenAuth or the resource server determines that they are expired or revoked. In fact since tokens can be revoked before they expire, it's a good idea to always be prepared for that.
The OAuth 2 spec draft 25 does in fact indicate that a refresh token should not be included in a response to the client credentials grant. From section 4.4.3:
4.4.3. Access Token Response
If the access token request is valid and authorized, the authorization server issues an access token as described in Section 5.1. A refresh token SHOULD NOT be included. If the request failed client authentication or is invalid, the authorization server returns an error response as described in Section 5.2.