How can I get the name and email from a token .
Structure of the token using jwt.io
http://prntscr.com/yzyf2b
Any help is appreciated.
Update full solution with the help of below posts so credits to them .
String jwtToken = token;
System.out.println("------------ Decode JWT ------------");
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
System.out.println("~~~~~~~~~ JWT Header ~~~~~~~");
Base64 base64Url = new Base64(true);
String header = new String(base64Url.decode(base64EncodedHeader));
System.out.println("JWT Header : " + header);
System.out.println("~~~~~~~~~ JWT Body ~~~~~~~");
String body = new String(base64Url.decode(base64EncodedBody));
System.out.println("JWT Body : " + body);
JSONObject jsonObject = new JSONObject(body);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));
A JWToken has the following structure Header.Body.Signature. Hence, first you should split the token into three parts, namely Header, Body and Signature.
For that you can use
String[] token_part = jwtToken.split("\\.");
then apply what you already have done but for the token_part[1] (i.e., the payload or Body), namely:
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
String a = new String(decoder.decodeBuffer(token_part[1]));
For the decoding part, alternatively, you can try this SO thread.
After that you can use the org.json.JSONObject to parse the JSON. An example:
public class Token {
public static void main(String[] args) {
String token = "{\"name\":\"john doe\", \"email\": \"john#mail.com\"}";
JSONObject jsonObject = new JSONObject(token);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));
}
}
Output:
john#mail.com
john doe
Full Example:
String jwtToken = token;
System.out.println("------------ Decode JWT ------------");
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
System.out.println("~~~~~~~~~ JWT Header ~~~~~~~");
Base64 base64Url = new Base64(true);
String header = new String(base64Url.decode(base64EncodedHeader));
System.out.println("JWT Header : " + header);
System.out.println("~~~~~~~~~ JWT Body ~~~~~~~");
String body = new String(base64Url.decode(base64EncodedBody));
System.out.println("JWT Body : " + body);
JSONObject jsonObject = new JSONObject(body);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));
Related
What I try to achieve:
iOS client sends a JWT token to the backend.
Backend (Java) calls https://appleid.apple.com/auth/token to verify the token.
what I have so far:
to make Apple verification call:
restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("client_id", clientId); // app_id like com.app.id
String token = generateJWT(); // generated jwt
map.add("client_secret", token);
map.add("grant_type", "authorization_code");
map.add("code", authorizationCode); // JWT code we got from iOS
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
final String appleAuthURL = "https://appleid.apple.com/auth/token";
String response = restTemplate.postForObject(appleAuthURL, request, String.class);
token generation:
final PrivateKey privateKey = getPrivateKey();
final int expiration = 1000 * 60 * 5;
String token = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, keyId) // key id I got from Apple
.setIssuer(teamId)
.setAudience("https://appleid.apple.com")
.setSubject(clientId) // app id com.app.id
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.setIssuedAt(new Date(System.currentTimeMillis()))
.signWith(SignatureAlgorithm.ES256, privateKey) // ECDSA using P-256 and SHA-256
.compact();
return token;
to get my private key from the file:
final Reader pemReader = new StringReader(getKeyData());
final PEMParser pemParser = new PEMParser(pemReader);
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
final PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();
final PrivateKey pKey = converter.getPrivateKey(object);
I confirmed my JWT has all required fields:
{
"kid": "SAME KEY AS MY KEY ID",
"alg": "ES256"
}
{
"iss": "Blahblah",
"aud": "https://appleid.apple.com",
"sub": "com.app.id",
"exp": 1578513833,
"iat": 1578513533
}
This line caught my attention:
map.add("code", authorizationCode); // JWT code we got from iOS
The authorizationCode is not a jwt
JSON Web Tokens consist of 3 parts separated by dots
but the authorizationCode has 4 parts like this:
text1.text2.0.text3
You are probably using the identityToken from the iOS app instead of the authorizationCode
This is how you retrieve it:
let authorizationCode = String(data: appleIDCredential.authorizationCode!, encoding: .utf8)!
print("authorizationCode: \(authorizationCode)")
Also good to have the following in mind for those who might come here after getting the same invalid_client error:
kid is the id for the private key from developer.apple.com/account/resources/authkeys/list
keyFile is the file holding the private key downloaded from developer.apple.com
teamID can be found by logging in to developer.apple.com and clicking on account, the teamID can be seen in the upper right corner
the value in aud should be https://appleid.apple.com
app_id is the bundle identifier for the app
In case it might help, here is a working solution in python to create a client_secret:
# $ pip install pyjwt
import jwt
import time
kid = "myKeyId"
keyFile = "/pathToFile/AuthKey.p8"
key = ""
with open(keyFile, 'r') as myFile:
key = myFile.read()
print(key)
timeNow = int(round(time.time()))
time3Months = timeNow + 86400*90
claims = {
'iss': teamID,
'iat': timeNow,
'exp': time3Months,
'aud': 'https://appleid.apple.com',
'sub': app_id,
}
secret = jwt.encode(claims, key, algorithm='ES256', headers={'kid': kid})
print("secret:")
print(secret)
client_secret = secret.decode("utf-8")
print(client_secret)
Save the clientSecret and appleToken into the local DB at login time with Apple ID.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
print("didCompleteWithAuthorization : -\(authorization)")
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
// Create an account in your system.
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName?.givenName
let email = appleIDCredential.email
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
return
}
StorageServices.storeInDefaults(object: idTokenString, key: "appleToken")
// Add new code below
if let authorizationCode = appleIDCredential.authorizationCode,
let codeString = String(data: authorizationCode, encoding: .utf8) {
StorageServices.storeInDefaults(object: codeString, key: "clientSecret")
}
default:
break
}
call the apple token revoke api.
func callRevokeTokenAPI() {
guard let clientSecret = StorageServices.readFromDefaults(key: "clientSecret") as? String else {return}
guard let appleToken = StorageServices.readFromDefaults(key: "appleToken") as? String else {return}
let parameters = "client_id=com.oxstren.Actofit-Wear&client_secret=\(clientSecret)&token=\(appleToken)&token_type_hint=access_token"
print(parameters)
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://appleid.apple.com/auth/revoke")!,timeoutInterval: Double.infinity)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let response = response as? HTTPURLResponse, error == nil else {
print("error", error ?? URLError(.badServerResponse))
return
}
print(response)
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
}
task.resume()
} //end function body.
I'm using jersey to call different Rest Api and I've searched for a solution to convert the response to java array or list this is the output :
[{"name":"TEST","number":22,"successNumber":11,"runnedNumber":20,"percentage":0.5},{"name":"SCENARIO","number":29,"successNumber":10,"runnedNumber":12,"percentage":0.34},{"name":"TESTCASE","number":11,"successNumber":6,"runnedNumber":9,"percentage":0.55}]
I tried resp.getEntity(String.class) but this returned a string and i need
to convert it to List or Array or any other data structure so i can manipulate the data because i'm trying to make charts.
this the method that i used to make the API Call:
public ClientResponse callApi(String url) throws IOException {
String name = "admin";
String password = "admin";
String authString = name + ":" + password;
String authStringEnc = new BASE64Encoder().encode(authString.getBytes());
System.out.println("Base64 encoded auth string: " + authStringEnc);
Client restClient = Client.create();
WebResource webResource = restClient.resource(url);
ClientResponse resp = webResource.accept("application/json")
.header("Authorization", "Basic " + authStringEnc)
.get(ClientResponse.class);
if(resp.getStatus() != 200){
System.err.println("Unable to connect to the server");
}
String output = resp.getEntity(String.class);
System.out.println("response: "+output);
return resp;
}
It can be achieved by following snippet:
String response = response.getEntity().toString();
JSONArray jsonArray = (JSONArray) new JSONParser().parse(response);
String[] stringArray = jsonArray.toArray(new String[jsonArray.size()]);
I solved it i used the objectMapper from jackson
String json = "json string";
ObjectMapper objectMapper = new ObjectMapper();
List<YourClass> listClass = objectMapper.readValue(json, new TypeReference<List<YourClass>>(){});
I want to convert JSON to a java object. I created a class and I wrote code like this.I am getting exception o/p:Unexpected character (c) at position 0
I'm getting the JSON data from the client. but when I try to convert JSON to java I'm getting an error
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);
WebResource webResource = client
.resource("my url");
String name = "adn";
String password = "12";
String authString = name + ":" + password;
String authStringEnc = new BASE64Encoder().encode(authString
.getBytes());
// System.out.println("Base64 encoded auth string: " +
// authStringEnc);
ClientResponse response = webResource.accept("application/json")
.header("Authorization", "Basic " + authStringEnc)
.get(ClientResponse.class);
String output = response.getEntity(String.class);
output = output.substring(13, output.length() - 1);
System.out.println(output);
JSONParser parse = new JSONParser();
counts count=new counts();
JSONObject jobj = (JSONObject)parse.parse(output);
JSONArray jsonarr_1 = (JSONArray) jobj.get("Counts");
// System.out.println(jsonarr_1.get(1));
JSONArray array = new JSONArray();
//Get data for Results array
for(int i=0;i<jsonarr_1.length();i++)
{
//Store the JSON objects in an array
//Get the index of the JSON object and print the values as per the index
JSONObject jsonobj_1 = (JSONObject)jsonarr_1.get(i);
System.out.println("Elements under results array");
System.out.println("\nPlace id: " +jsonobj_1.get("college_name"));
System.out.println("Types: " +jsonobj_1.get("college_epass_id"));
}
I am getting the JSON data from client. I want to convert the JSON to java object. I created pojo(counts) class also. The json data is like this:
o/p:college_name":"GPT n,
Kakda","college_epass_id":128},{"college_name":"GT,
am","college_epass_id":2946}
error:
Unexpected character (c) at position 0.
Use of Jackson
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> map = mapper.readValue(json, Map.class);
Your classes will be some like
public class CollegeList{
#JsonProperty("counts")
public List<College> counts;
}
public class College{
#JsonProperty("college_name") public String college_name;
#JsonProperty("college_epass_id") public int college_epass_id;
}
You can convert the json into respective object by
CollegeList colleges = mapper.readValue(jsonString, CollegeList .class);
Sharing Reference Link for more details.
I think your issue is that you are truncating the response on this line...
output = output.substring(13, output.length() - 1);
This will make the JSON string invalid
Perhaps you should consider removing this line of code or creating a separate variable to store the substring.
so learning still but i'm getting an Error 401 unauthorised back from the code below. I know that the OAuth header works as it works in postman so i'm assuming there is a problem with the POST request / Auth header? Any ideas?
//set timestamp
Long timestamp = System.currentTimeMillis()/1000;
//set nonce ***** call from main system*************************************************************
String aString = randomAlphaNumeric(11);
// other stuff
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
String url = "aURL";
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// String auth = Base64.getEncoder().encodeToString(credentials.getBytes());
List<NameValuePair> oauthHeaders = new ArrayList<>(9);
oauthHeaders.add(new BasicNameValuePair("oauth_consumer_key", "aKey"));
oauthHeaders.add(new BasicNameValuePair("oauth_nonce", aString));
oauthHeaders.add(new BasicNameValuePair("oauth_timestamp", String.valueOf(timestamp)));
oauthHeaders.add(new BasicNameValuePair("oauth_signature_method", "HMAC-SHA1"));
oauthHeaders.add(new BasicNameValuePair("oauth_version", "1.0"));
//generate signature
//encode
String encodedURL = encode(oauthHeaders.toString());
System.out.println("encoded URL:" +encodedURL);
//form base string
String baseString = "POST&"+encode(url).toString()+encodedURL;
System.out.println("Base String: "+baseString);
//form signature
byte[] byteHMAC = null;
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec spec;
if (null == secretKey) {
String signingKey = encode(secretKey) + '&';
spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");
} else {
String signingKey = encode(secretKey) + '&' + encode(secretKey);
spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");
}
mac.init(spec);
byteHMAC = mac.doFinal(baseString.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
String signature = new BASE64Encoder().encode(byteHMAC);
System.out.println("oauth signature: "+signature);
//set signature to params
oauthHeaders.add(new BasicNameValuePair("oauth_signature", signature));
String test = "OAuth "+oauthHeaders.toString();
headers.set("Authorization", test);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("Name",name.toString());
map.add("Region",region.toString());
HttpEntity<MultiValueMap<String, String>> requestEntity= new HttpEntity<MultiValueMap<String, String>>(headers, map);
System.out.println(requestEntity);
ResponseEntity<String> response= restTemplate.exchange(url ,HttpMethod.POST, requestEntity, String.class);
System.out.println(response.toString());
HttpStatus status = response.getStatusCode();
status.toString();
if(status.equals("200")){
Notification.show("Employer" + name +" added successfully");
}
else{
Notification.show("Unsuccessful, error: "+status);
}
}
removed the URL and consumer key / signature for obvious reasons.
The following System out prints might help as well:
encoded params:
%5Boauth_consumer_key%3aKey%2C%20oauth_nonce%3DWZU8H1B5JA6%2C%20oauth_timestamp%3D1511621759%2C%20oauth_signature_method%3DHMAC-SHA1%2C%20oauth_version%3D1.0%5D
Base String: POST&https%3A%2F%2Fapi.test.payrun.io%2FEmployer%5Boauth_consumer_key%3aKey%2C%20oauth_nonce%3DWZU8H1B5JA6%2C%20oauth_timestamp%3D1511621759%2C%20oauth_signature_method%3DHMAC-SHA1%2C%20oauth_version%3D1.0%5D
oauth signature: DlRJGSzgRIItzz+LzMbgnIfbOqU=
The value of oauth_signature is wrong. You are using asignature as the value of oauth_signature, but you have to compute the correct value for your request and set it to oauth_signature. If the value of oauth_signature is wrong, the server will reject your request. See "3.4. Signature" in RFC 5849 (The OAuth 1.0 Protocol) for details.
For anyone who wants to make this work then please see below for a complete OAuth Generator example :):
public class oAuthGenerator {
private String httpMethod;
private String params;
private String url;
//Required for percent encoding
private static final String ENC = "ASCII";
//Required for nonce
private static final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
//As provided by Payrun.io
private static final String secretKey = "aSecretKey";
//As provided by Payrun.io
private static final String consumerKey ="aConsumerKey";
private List veriList;
//Constructor for setting signature base string values.
//#Param url needs to be percent encoded
//#Param params needs to be percent encoded, this is done #Method generateOAuth()
public oAuthGenerator(String httpMethod,String url )throws Exception {
veriList= new ArrayList<String>();
veriList.add("POST");
veriList.add("GET");
veriList.add("PUT");
veriList.add("DELETE");
if (veriList.contains(httpMethod)){
this.httpMethod = httpMethod+"&";}
this.url = URLEncoder.encode(url,ENC)+"&";
}
//A method used to generate the OAuth Authorization header
//#Method randomAlphaNumeric() calls internal method using instance variable ALPHA_NUMERIC_STRING
//#Method getSignature() returns String HMACSHA1 > Base64 encoded value of httpMethod,url,params
public String generateOAuth()throws Exception{
//Set timestamp as seconds from 01-01-1970
Timestamp timestamp = new Timestamp(System.currentTimeMillis()/1000);
Long aTimestamp = timestamp.getTime();
//Set nonce which is a 10 digit random, non repeating alpha-numeric value
String aNonce = randomAlphaNumeric(10);
//Normalize and form param string
String normalizedParams = "oauth_consumer_key="+consumerKey+"&"+"oauth_nonce="+aNonce+"&"+"oauth_signature_method="+"HMAC-SHA1"+"&"+"oauth_timestamp="+ aTimestamp.toString()+"&"+"oauth_version="+"1.0";
//Percent encoded params
params = URLEncoder.encode(normalizedParams,ENC);
//Set signature variable
String signature = getSignature();
//place into required format
String oAuthResult = "OAuth "+"oauth_version="+"\"1.0\""+","+"oauth_consumer_key="+"\"" + consumerKey + "\""+","+"oauth_signature_method="+"\"HMAC-SHA1\""+","+"oauth_timestamp="+"\""+aTimestamp+"\""+","+"oauth_nonce="+"\""+aNonce+"\""+","+"oauth_signature="+"\""+signature+"\"";
return oAuthResult;
}
// A method designed to return a hashed and base64 encoded value.
//#Param aString holds HMAC-SHA1 and Base 64 encoded value of variables httpMethod,url,params
//#Param result holds percent encoded value of aString
private String getSignature()
throws Exception {
//form base string
StringBuilder base = new StringBuilder();
base.append(httpMethod);
base.append(url);
base.append(params);
//Set SecretKey of variable secretKey using HMAC-SHA1 algorithm
SecretKey signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
// Get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
// Compute the hmac on input data bytes, then encode to Base64
String aString = Base64.getEncoder().encodeToString(mac.doFinal(base.toString().getBytes(ENC))).trim();
//Percent encoded the Base64 value
String result = URLEncoder.encode(aString, ENC);
return new String(result);
}
//Required for nonce, returns a random alpha numeric value by using variable ALPHA_NUMERIC_STRING
private static String randomAlphaNumeric(int count) {
StringBuilder builder = new StringBuilder();
while (count-- != 0) {
int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length());
builder.append(ALPHA_NUMERIC_STRING.charAt(character));
}
return builder.toString();
}
}
I am trying to load a url with headers and trying to get my accessToken
Here is the code
String oauthToken = urls[0];
String tokenVerifier = urls[1];
String responseBody = null;
try {
String url = "https://api.copy.com/oauth/access?oauth_verifier=" + tokenVerifier;
String uniqueID = UUID.randomUUID().toString();
String authorization = "OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""+ Constants.COPY_CONSUMER_KEY
+"\", oauth_signature=\""+ Constants.COPY_SECRET +"&" + tokenVerifier "\", oauth_nonce=\""+ uniqueID
+"\", oauth_timestamp=\""+String.valueOf(Calendar.getInstance().getTimeInMillis())+"\" , oauth_token=\""+ oauthToken +"\"";
The response gives me error
oauth_problem=signature_invalid&debug_sbs=GET&https%3A%2F%2Fapi.copy.com%2Foauth%2Faccess&oauth_consumer_key%3DCtu6CtdN1PWRo5DstoxgaaIQWZkeeWNg%26oauth_nonce%3D10525625%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1425400347545%26oauth_token%3D6aNkypb7wZoI7dbJiSrtItOTGmpaG0RL%26oauth_verifier%3D496cb46091352c4788603dcfb6e0cfb5%26oauth_version%3D1.0oauth_error_code=2000
What is wrong with my signature, same method is working for ios
You are sending the ouath_token that you have just received when you have to calculate a new Token using that received token and the request_token_secret. This new token is what you need to send as oauth_token parameter in your request.
Check my python code here.