I am using JWT for API authentication using RS256 private/public key.
At my client side I am using Vuejs/Angular/React, I am tempted to use JsonWebToken to do client JWT token verification for expiry date and issuer:
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {
// if issuer mismatch, err == invalid issuer
});
Do you think is a good idea to expose public key, although public key is meant for distribute?
The public key can be published 'publicly' with no harms. The public key is used to verify that the signature isn't manipulated while the private key is the one which shall be kept secret as it is the one that signs the payload. So your client needs to know only if the payload hasn't been manipulated. More details here
Related
Is it possible to validate the JWT token in a reactjs frontend application or does it require server side node/other framework to validate the signature?
From what I understand the JWT token has a signature portion that has to be validated against a secret key. So for this to happen security you require this part of the validation to be perform on the server side/backend.
Is this correct?
You can decode the JWT's payload on the frontend without the key, but you'll need the key to validate the token (meaning verify it was generated using the given key).
Exposing the key to the frontend makes JWT useless because anyone can generate tokens with any payload value, signed with your key. Therefore, any validation of the token should be done on the server side with the protected key.
Example frontend decode. Credit to #Peheje:
function parseJwt (token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
}
I want to prevent my secret data (e.g. 'password') while sending them in my requests.
I'm using React on Frontend and MongoDB on Backend side.
Actually, I'm registering a user to database with his salted and hashed password like this:
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) {
next()
}
const salt = await bcrypt.genSalt(10);
console.log('this.password: ', this.password);
// password coming form Frontend is not still protected here, like '1234'
this.password = await bcrypt.hash(this.password, salt);
// password is protected like '$2a$10$gxNPkFvqRIFZPyMsB.Dmf.G52yQntT3LxJQHuteCaSZCpUZ0RPkdm'
})
But I want to protect the sensitive data also on the way (for example from 'man in the middle attacks').
So, how should I implement the sending of user password as protected, or what is the best experienced way to do it?
Thanks.
Use asymmetric encryption.
Generate a public-private key pair, encrypt the password with the public key on the frontend, send the ciphertext to the backend, decrypt with the private key on the backend.
I have an existing api that generates and uses jwt's with a header as follows
{
"typ": "JWT",
"alg": "HS256"
}
The api uses JWT bearer authentication
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { "Any" },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
I now want to use identity server for a client I want to integrate with.
How can I get Identity server to sign the token in the way that the existing api expects it (HS256).
IdentityServer does not support symmetric keys.
When I place the below in a React component that queries the user model I am able to get the entire user object as queried by graphQL including the id property:
console.log(this.props.data.user)
But when I try to access the id property from code:
console.log(this.props.data.user) // undefined
console.log(this.props.data.user.id)
// error cannot get property of undefined
My first guess is that this is a security feature; I am using Auth0 and Graphcool.
But I may just be going about this in a backwards way. If so, any help on accessing the user id in the correct manner would be appreciated.
Thanks
This is covered in the FAQ article on the logged in user.
Obtaining a Signed JWT with Auth0
The user query returns the currently authenticated user. So first we have to think about how the authenticated user is determined.
The current state-of-the-art is using verified JWT and passing them as the Authorization header.
After entering valid credentials in Auth0 Lock, it returns a JWT that is signed with your secret Auth0 key. This signed JWT is sent to the GraphQL server where we'll use your Auth0 key to verify it and if it belongs to a valid user, the request is authenticated.
Setting the Authorization Header with Apollo Client
So I suspect that you're simply not passing a valid Authorization header. With Apollo, you can use this to ensure passing the token if it is present. Note that we'll use local storage for storing the token from Auth0 Lock:
const networkInterface = createNetworkInterface({ uri: 'https://api.graph.cool/simple/v1/__PROJECT_ID__' })
// use the auth0IdToken in localStorage for authorized requests
networkInterface.use([{
applyMiddleware (req, next) {
if (!req.options.headers) {
req.options.headers = {}
}
// get the authentication token from local storage if it exists
if (localStorage.getItem('auth0IdToken')) {
req.options.headers.authorization = `Bearer ${localStorage.getItem('auth0IdToken')}`
}
next()
},
}])
const client = new ApolloClient({ networkInterface })
Check this Auth0 example code or the live demo to see how it works.
You might also be interested in this answer on authorization (permissions).
I'm currently writing an angular application that first authenticates against think texture identityserver3.
This works fine, and I receive the bearer token without any issues.
When I use my token on an call to my API, I'm authenticated. I can see my userid, but have lost my claims (username, roles,...).
What do I have to do for transferring my claims with my token, or getting the roles from the identityserver?
You can tell Identity Server to include specific claims in an access token by adding that claim to your API's Scope.
Example:
var apiScope = new Scope {
Name = "myApi",
DisplayName = "My API",
Type = ScopeType.Resource,
Claims = new List<ScopeClaim> {
new ScopeClaim("myClaimType")
}
};
You can also use the AlwaysIncludeInIdToken property of ScopeClaim to include the claims in identity tokens as well as access tokens.
See https://identityserver.github.io/Documentation/docsv2/configuration/scopesAndClaims.html for more info.
We are doing something very similar using MS Web API 2 and a Thinktecture Identity Server v3.
To verify the user's claims we created an Authentication Filter, and then called the Identity server directly to get the user's claims. The bearer token only grants authentication and it is up to the API to get the claims separately.
protected override bool IsAuthorized(HttpActionContext actionContext)
{
string identityServerUrl = WebConfigurationManager.AppSettings.Get("IdentityServerUrl") + "/connect/userinfo";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = actionContext.Request.Headers.Authorization;
var response = httpClient.GetAsync(identityServerUrl).Result;
if (response.IsSuccessStatusCode)
{
string responseString = response.Content.ReadAsStringAsync().Result;
Dictionary<string, string> claims = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseString.ToLower());
... Do stuff with your claims here ...
}
}
}