I have created a JWT Token in Spring Boot for storing User Details. When I use Jwttokenutil.getUsernameFromToken(authToken) [ authToken is the token passed ] method I get the data set to Subject. Similarly I want to get the data set to Payload which contains other User Details. But I am not able to get it.
======= Below is my token generation method / code : ========
public String generateToken(HashMap<String, Object> userData,String subject)
{
String jwtToken="";
System.out.println("in generate token method : " + subject);
jwtToken = Jwts.builder()
.setSubject(subject) // subject is dbname
.claim("userDetails", userData)
.setPayload(userData.toString())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 60*60*5*1000))
.signWith(SignatureAlgorithm.HS256, "secretkey")
.compact();
System.out.println("userData " + userData);
return jwtToken;
}
======= Below is the method I have created to get the Payload data ======
public Object getPayloadFromToken(String token)
{
Claims body= Jwts.parser()
.setSigningKey("secretkey")
.parseClaimsJws(token)
.getBody();
System.out.println("userdet==========> " + body.get("userDetails") );
return body.get("userDetails");
}
=== But I am getting this error ===
java.lang.IllegalStateException: Both 'payload' and 'claims' cannot both be specified. Choose either one.
Late but I hope it serves someone.
.setPayload (...) is used to create a payload defined by us, the error that you get with claims is because .setPayload (...) should not be used with any of the following
.setSubject (...)
.claim (...)
.setIssuedAt (....)
.setExpiration (...)
Hi Sorry for late Answer. Actually you can't add both claims and payload. You can user either only one method in that. Payload method accepts only string, So add values to the token you can use the method add claims. Follow the below code structure. It will generates proper JWT token using details.
public String generateToken(Authentication authentication) {
Details user = (Details) authentication.getPrincipal();
Map<String, Object> claims = new HashMap<>();
claims.put("name", user.getName());
claims.put("email", user.getEmail());
return Jwts.builder().setSubject(user.getUsername()).addClaims(claims)
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + tokenExpirationTime))
.signWith(SignatureAlgorithm.HS512, secretKey).compact();
}
Follow this method need any updates and changes. Please comment below....
Related
I have 0 experience in coding in APEX so I would greatly appreciate your help and support with this question!
I would like to figure out a way to automate the deletion of an Aircall User if an SF user is deleted. Let us assume that every SF user has an Aircall ID that is present in their User profiles, stored in a field called 'Aircall ID'. This is what I will need to form the delete request.
I want that when a user is deleted on Salesforce, it triggers a delete request to Aircall sending the value that was previously stored in the Aircall ID field to the specific endpoint in question.
I need help figuring out how to write an APEX trigger that sends the Aircall ID to the class (to be triggered after the user is deleted) and finally how to automatically trigger the execution of this class after the ID has been received in order to complete the User deletion on Aircall's platform.
public class deleteAirCallUser {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setMethod('DELETE');
string encodedCredentials = 'apikey';
String authorizationHeader = 'Basic ' + encodedCredentials;
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
request.setHeader('Authorization', authorizationHeader);
string AircallUserId = //should be the Aircall userID from the deleted profile
request.setBody(AircallUserId);
request.setEndpoint('https://api.aircall.io/v1/users/'+ Aircall userID);
HttpResponse response = http.send(request);
if (response.getStatusCode() == 200) {
Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
System.debug(results);}
else{
Map<String, Object> results_2 = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
System.debug(results_2);
}
}
Thank you for your help!
https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_user.htm
"You can’t delete a user in the user interface or the API. You can deactivate a user in the user interface; and you can deactivate or disable a Customer Portal or partner portal user in the user interface or the API. Because users can never be deleted, we recommend that you exercise caution when creating them."
For deactivations you'll need something like this. (It's not written to best practices, ideally the trigger would be "thin" and actual processing offloaded to helper class. Also it assumes you mass update max 10 users at a time because that's the limit of callouts.
trigger UserTrigger on User (after update){
Set<String> toSend = new Set<String>();
for(User u : trigger.new){
User oldUser = trigger.oldMap.get(u.Id);
// have we deactivated them?
if(!u.isActive && oldUser.isActive && String.isNotBlank(u.AirCallId__c)){
toSend.add(u.AirCallId__c);
}
}
if(!toSend.isEmpty()){
sendAirCallDeletes(toSend);
}
// This should be in a helper class, it looks bizarre to have functions defined in trigger's body
#future
static void sendAirCallDeletes(Set<String> toSend){
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setMethod('DELETE');
String encodedCredentials = 'apikey';
String authorizationHeader = 'Basic ' + encodedCredentials;
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
request.setHeader('Authorization', authorizationHeader);
for(String airCallId : toSend){
request.setBody(airCallId);
request.setEndpoint('https://api.aircall.io/v1/users/'+ airCallId);
try{
HttpResponse response = http.send(request);
System.debug(response.getStatusCode());
System.debug(response.getBody());
System.debug((Map<String, Object>) JSON.deserializeUntyped(response.getBody());
} catch(Exception e){
System.debug(e);
}
}
}
}
You might want to read up about "named credentials" (don't store the api keys etc in code), why we need "#future" trick when we want to make callout from a trigger, how to check for limit of calls you can make in single transaction... But should be a start?
I am writing a REST client in C#.Net using RestSharp. There are two API calls - one is "Auth" call and second is "getKey" call. The "Auth" call throws back a "Auth token"in the response, and I'd like to parse that token from the response, and pass it as an header to the second "getkey" call. Please advise with examples
I have given some sample to achieve your scenario. Please use the below example and do the modification as per your requirement.
RestUtils Class:
Add the Request Header, If your application is expected some additional headers.
class RestUtils
{
private static readonly RestClient _restClient = new RestClient();
public static void SetBaseURL(String host)
{
_restClient.BaseUrl = new Uri(host);
}
public static string GetResponse(String endpoint, String token)
{
var request = new RestRequest(endpoint, Method.GET);
request.AddHeader("Accept", "application/json");
request.AddHeader("Authorization", token);
IRestResponse response = _restClient.Execute(request);
return response.Content;
}
public static string GetToken(String endpoint)
{
var request = new RestRequest(endpoint, Method.GET);
request.AddHeader("Accept", "application/json");
IRestResponse response = _restClient.Execute(request);
return response.Content;
}
}
TestClass:
In your test class you can add the below steps and you can get the result as expected. First two lines will be executed and give the authentication token as output. So, you can use the retrieved token in the subsequent lines for other API. In another way, you can create one property class and set the retrieved token value .So, that you can access the token from various class.
//Specify the Base URI of your Token Specific API
RestUtils.SetBaseURL("https://login.microsoftonline.com/");
//Specify the End Point of your Token Specific API
String token = RestUtils.GetToken("/oauth2/token");
//Specify the Base URI of your actual Test API
RestUtils.SetBaseURL("XXXXXXX");
String response = RestUtils.GetResponse(token);
I am facing Signature exception while adding security to my Spring Rest services. Please help.
io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354)
//Make Token
String token = Jwts.builder()
.setSubject(((User) auth.getPrincipal()).getUsername())
.signWith(SignatureAlgorithm.HS512, SECRET.getBytes("UTF-8"))
.compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
// Decoding token
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
String jwt = token.replace(TOKEN_PREFIX, "");
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET.getBytes("UTF-8"))
.parseClaimsJws(jwt)
.getBody();
if (claims.getSubject() != null) {
return new UsernamePasswordAuthenticationToken(claims.getSubject(), null, getAuthorities());
}
}
When I am printing both, I am getting the below text. One is having extra space. This is happening only when I am hitting the service using Rest client. Test classes are working fine.
makeToken= eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJza3AifQ.XUEsUFF3qm6fOeCG8xDLuRWjyd4kOh4g01olU_BsRyfqyI66MRhqmK-mxrAWsD17Ylmj-fZRRZUTRqxCQixxXQ
decodeToken=
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJza3AifQ.XUEsUFF3qm6fOeCG8xDLuRWjyd4kOh4g01olU_BsRyfqyI66MRhqmK-mxrAWsD17Ylmj-fZRR ZUTRqxCQixxXQ
It's late but worth If someone is facing the same issue while decoding JWT token.
Library GitHub link:
https://github.com/auth0/JWTDecode.Android
Implementation:
implementation ('com.auth0.android:jwtdecode:1.2.0'){
exclude group: 'com.android.support', module: 'appcompat-v7'
}
Code:
// token: eyJ0eXAiOiJKV1QiLCJhbxxxxxxx9.eyJpZC*********************UEFUSUVOVCIsImV4cCI6MTU2NTY5MzU5MCwib3JpZ0lhdCI6MTU2NTA4ODc5MH0.ZhPpZSFZL6EY-Mwrw0F*********MYmbw
private void getExpDate(String token) {
JWT jwt = new JWT(token);
Log.e(TAG,"Claim - id:"+jwt.getClaim("id").asString()+" - username:"+jwt.getClaim("username").asString()+" - role:"+jwt.getClaim("role").asString()+" - exp:"+jwt.getClaim("exp").asString());
}
Logcat Result:
E/PatientLogin: Claim - id:cd5dbe61-xxxx-xxxx-xxxx-xxxxxx - username:xxxx#gmail.com - role:PATIENT - exp:1565693590
Test JWT Token:
If you want to check your JWT token then use below link.
https://jwt.io/
OR
Here is another method which might work for you as well. This will help to avoid using a third-party library.
Reference: Orignal post
decoded(token);
public static String decoded(String JWTEncoded) {
String[] split = JWTEncoded.split("\\.");
Log.e(TAG, "Header: " + getJson(split[0]));
Log.e(TAG, "Body: " + getJson(split[1]));
return getJson(split[1]);
}
private static String getJson(String strEncoded){
String str_dec = "";
try {
byte[] decodedBytes = Base64.decode(strEncoded, Base64.URL_SAFE);
str_dec = new String(decodedBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str_dec;
}
I am attempting to get eBay product IDs using the GetOffers request by sending it a product SKU.
My code is below, the problem I am currently having is that when I try to test this code is returns a 401 unauthorized. It's not returning any specific error code or anything descriptive.
I know my access token is valid I can't find any good examples on how to use this request.
public string getEbayOffers(string sku)
{
HttpResponseMessage response;
string accessToken = "tokenhere";
string param = Convert.ToBase64String(Encoding.ASCII.GetBytes(accessToken));
string url = $"sell/inventory/v1/offer?sku={sku}";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://api.ebay.com/");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", param);
response = client.GetAsync(url).Result;
}
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsStringAsync().Result;
}
return null;
}
No need to convert your token to base64. The correct format should be "Bearer YOUR_USER_TOKEN". Replace YOUR_USER_TOKEN with your own token string.
Access token should be enough for getting offers but maybe you can try to use user token if above doesn't work.
I'm looking for a way to exchange short-lived access tokens for long-lived access tokens in our backend as described by Facebook here. How to do this with facebook4j?
I have done something like this to exchange old token for new token:
private AccessToken refreshToken(Facebook facebook, AccessToken currentToken) throws Exception {
String clientId = configuration.getString(ConfigurationKeys.SOCIAL_FACEBOOK_CLIENTID);
String clientSecret = configuration.getString(ConfigurationKeys.SOCIAL_FACEBOOK_CLIENTSECRET);
Map<String, String> params = new HashMap<String, String>();
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
params.put("grant_type", "fb_exchange_token");
params.put("fb_exchange_token", currentToken.getToken());
RawAPIResponse apiResponse = facebook.callGetAPI("/oauth/access_token", params);
String response = apiResponse.asString();
AccessToken newAccessToken = new AccessToken(response);
facebook.setOAuthAccessToken(newAccessToken);
return newAccessToken;
}
I think this can be done after each login so the access token is refreshed even if it still valid - you will just get newer token with 60 days of validity.
What do you think?
I am extending the Facebook class. The method they provided don't work. So I wrote another function which does gives a long lived token but it's somehow invalid ( I tried testing the new token with token_debug and tried to generate client_code with it)! I will update you if I get to work it out. If you can solve it, please update me.
Please remember I didn't clean up the code as I am still writing on it.
public function GetExtendedAccessToken()
{
//global $CONFIGURATIONS;
//$info=$this->api($path,'GET',$args);//doesn't work as api overrides method to post
$string=file_get_contents("https://graph.facebook.com/oauth/access_token?client_id=".$this->getAppId()
."&client_secret=".$this->getAppSecret()
."&fb_exchange_token=".$this->getAccessToken()
."&grant_type=fb_exchange_token"
."&redirect_uri=".$redirectUri);
var_dump($string);
$tokenInfo=explode('&',$string);
$exAccessToken=str_replace('access_token=', '', $tokenInfo[0]);
$expiresAt=str_replace('expires=', '', $tokenInfo[1]);
echo "expires in ". (time()-$expiresAt);
var_dump($exAccessToken);
return $exAccessToken;
}
It works now. Some times I get an error for not providing redirect_uri.