App will receive a token (string) from server. I want to sign this token with private key. I will pass on corresponding public key and signed token back to server in next request. Now server will validate that token using public key to check whether request is coming from authenticated user.
How to achieve this?
Related
I am trying to implement OAuth2.0 authorization framework in one java based web project.
I use MS Azure as the Resource Owner(R.O) + Auth Server(A.S).
I also created some customized scopes(i.e. attributes) to be included in the Access token.
My question is - when client receives access token from Azure AD and forwards it to the Resource Server, how does resource server(RS) validates this access token ? How can RS decode the token and read the "scope".
The RS was never connected to R.O or A.S.
Note. I dont want to use OIDC. I want to achieve this only through OAuth2
I assume token here you are referring is JWT token. Decoding JWT token is not a big deal, as the token is just Base64 encoded.
But the validating the token is important.
There are 2 ways the validate the token (the token is intact and not tempered in between):
If the token was signed using the symmetric algorithm (HS256, ...) then the same key needs to be with the RS as it was used by AS. I guess, in your case it won't be possible. Because you will not have a key with you.
If the token was signed using the asymmetric algorithm (RS256, ...). AS will use 'private key' to sign the token and RS will use corresponding public key to validate the token.
Note: the asymmetric key algorithm is CPU intensive task for RS to validate the token.
Following are the two options I can see so far:
Client sends RS are pre-provisioned with client_id and client_secret.
Client_Id and client_secret shall be generated by
Azure AD when subscriber registers the APP. When client sends
access token to RS, client also includes the "code" it received from
Azure AD (i.e. Resource Owner which is Azure AD). RS can now trigger a
GET request with the "code" + client_id. Azure AD can then issue an
access token back to the RS. Here RS can map the checksum and verify
if the access token is same(i.e. authorized).
Client sends access token to RS. RS decodes the token with base64 and only checks the expiry and client Id.
If the expiry is valid and client Id is same then RS concludes the token to be valid.
1st option seems to be more secured where RS can validate the access token and can also refresh the tokens if required.
So i read about how authentication is done using JWT, where we basically verify if the token is valid using a private key (assuming RSA is the algortihm). And if the token is valid, then the user is considered authenticated. And I also read about session authentication where we check if the user supplied session id (through cookie), exist in the session store (assuming mysql / redis is used to store session). If it exist, then the user is considered authenticated.
But how do we use JWT and session for authorization ? Lets consider an action such as GET invoice , whereby a user can only view the invoice that he owns.
If we consider the user is already authenticated,
how do we check if the user is authorized if we are using JWT?
And how do we do it for session ?
You are probably confusing the things. One of the benefits using JWT is to avoid maintaining sessions which is big bottle neck in scaling.
JWT (Json Web Token) carry all the information that would require it to get authenticated, you don't need to maintain the session. Every single HTTP request to server will carry JWT that would contain necessary user claims including the signature. On server you will validate the signature to verify if the token is valid or not. You can verify the token without maintaining any session and there are number of ways to do it.
Since JWT is essentially a Json object (Header, Body , Signature) , you can put in claims (emails, roles, profile etc) in JWT body. Once you verify the token , you can extract the claims including any roles and check if user is authorized to access the resource.
You must look into Open ID Connect and Tokens here
Im looking to create an angular application which login against a new authentication server created in springboot and return a jwt.
The idea is to create the application to be able to generate and sign the jwt token with a private key based on the user/password provided in the screen, the authentication server will validate the login information in database and generate the jwt token.
After that, a request will be sent to another microservice and in here I need to be able to validate the token, but this microservice wont be connected to the authentication service or database in any way, it will just validate the integrity of the token using a public key.
Im looking everywhere and I dont find the clue to be able to validate the token, I found this piece of code but for some reason when I execute the rest API exposed this code is not executed:
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream(), Charset.defaultCharset());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
Does what im trying to do makes any sense?
Thanks
Regards
Your auth server will will need to be the single issuer of JWTs to your microservices. So, when a user logs in and successfully authenticates, your auth server will issue a JWT signed with a private key (signing MUST be asymmetric - RS256 is one example) you keep on the auth server only; do not give this private key to other microservices that you wish to validate JWTs inside of. What you can do is derive a public key based on the private key you sign your tokens with and publish that to an endpoint on your auth server that requires no authentication - the public key will be represented in the form of a JWK (see link to spec). Google does something similar here. Then, in each of your microservices, you will need to devise a way to make a GET request to the public key endpoint on your auth server every X minutes and cache the public key in each microservice.
Then whenever a request comes into one of your microservices, you grab the JWT, check its validity, and grant access/authorization if the token is valid. The beauty of using a private/public key pair and asymmetric key signing is that you can validate a token based on the public key alone, but not sign it. So as long as each service has the public key from your /cert endpoint, they can validate a token without ever needing to talk to the auth server or knowing the private key.
This will require a little more work up front, but will yield you massive amount of ease, flexibility, and peace of mind in the future knowing only one source knows your private key.
I suggest using this library to do JWT validation.
The overall architecture will end up looking something like this:
What I want to achieve:
Safely allow users to connect their accounts to different social medias using a Single Page Application.
What I am doing:
I am using an SPA and therefor utilizing JWT as my user authentication method. I am passing the JWT token in the OAuth call with Laravel Socialite like this:
return Socialite::driver($provider)
->with(['provider' => $provider, 'token' => $token])
->redirectUrl($redirectUri)
->stateless()
->redirect();
On the callback I get the user based on the token. Using this method allows the third party provider to get access to the JWT token. Which is very unsafe.
My Question(s):
Is there any better way to do this? Should I use some kind of hash + salt + secret?
You should check the JWT.
JSON Web Tokens are an open, industry standard RFC 7519 method for
representing claims securely between two parties.
JWT Token composes of three parts, header, payload and verify signature.
You are using stateless authentication and the only way to authenticate the user is by the JWT Token. To authenticate the user after redirect, you should create a payload containing application's user id, and pass to the third party provider, so that when redirect, they will pass the JWT token back to you.
It is no problem to pass the JWT Token to third party provider, but be aware that the payload should not contain any sensitive data. If the payload is somehow sniffed, it will not have any harm because, if hacker is trying to change the payload, the verify signature helps and the application cannot verify the token and the application will throw exception.
The signature is used to verify that the sender of the JWT is who it
says it is and to ensure that the message wasn't changed along the
way.
Is there a recommended way to revoke another user's access in Identity Server 4? The use case I'm looking at is an Administrator revoking system access for a currently logged in user.
I've read the documentation for the Revocation Endpoint and can see how that can be used by a user to revoke their own access. But how can this be done when the Administrator wouldn't know what a particular user's access token is?
Same goes for the End Session Endpoint I suppose, how would the Admin know their ID Token?
What I've tried so far is implementing an IProfileService and checking the user's account is valid in the IsActiveAsync method. In our customer db I can deactivate their account and this has the desired effect of redirecting them to to the Login page. But the tokens and session are still 'alive'. Would this be a good place to end session and revoke access token?
Or is persisting user tokens to the database an option?
Update
Based on the answer from #Mashton below I found an example of how to implement persistence in the Identity Server docs here.
Creating the data migrations described there will persist tokens to [dbo].[PersistedGrants] in the Key column. I was confused at first since they didn't look anything like my reference access tokens but after a little digging I found that they are stored as a SHA-256 hash. Looking at the DefaultGrantStore implementation in Identity Server's GitHub the Hashed Key is calculated as follows ...
const string KeySeparator = ":";
protected string GetHashedKey(string value)
{
return (value + KeySeparator + _grantType).Sha256();
}
... where the value is the token and the _grantType is one of the following ...
public static class PersistedGrantTypes
{
public const string AuthorizationCode = "authorization_code";
public const string ReferenceToken = "reference_token";
public const string RefreshToken = "refresh_token";
public const string UserConsent = "user_consent";
}
Using persisted grants doesn't give me the original access token but it does allow me the ability to revoke access tokens since the [dbo].[PersistedGrants] table has the SubjectId.
Update 2 - Identity Server keeps creating tokens
I created an implicit mvc client and after successful login I'm dumpimg the claims on the screen. I delete the access token from the persisted grant db then use Postman to end the session in the End Session Endpoint (using the id token in the claims). When I refresh the browser I'd expect the user to get redirected to the login screen but instead they get a new access token and a new id token. The Client.IdentityTokenLifetime is only 30 seconds.
Any ideas of what I'm missing here?
You can only revoke Reference tokens not JWTs, and yes those need to be stored in a db. Have a look at the IPersistedGrantStore (of the top of my head, so may have got the name wrong), and you'll see the structure is pretty simple.
Once you've got them stored, you can obviously do anything you like admin-wise, such as change the expiry or just outright delete them.