For creating firebase custom auth tokens, I am using third party JWT library (https://github.com/jwtk/jjwt)
In this library, there is an option to add firebase Custom Token Claims like (alg, iss,sub,aud,iat etc.)
All firebase information is available at https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library
private_key = "-----BEGIN PRIVATE KEY-----... -----END PRIVATE KEY-----";
I had passed private key in signWith method with encoding in base64
val encodeKey = Base64.encode(privateKey.toByteArray(), android.util.Base64.DEFAULT)
val jwt = Jwts.builder().setIssuer("firebase-adminsdk-kywht#...")
.setSubject("firebase-adminsdk-kywht#...")
.setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
.setExpiration(calendar.time) //a java.util.Date
.setIssuedAt(Date())
.setId(UUID.randomUUID().toString())signWith(SignatureAlgorithm.RS512 ,encodeKey).compact()
I have used the above code but it did not work.
Anyone knows how to pass a private key to generate token?
first thing is whether you had missed a dot in your code acccidentally or not so put that and the parameters for signWith() is not correct i.e. first parameter is key and second one is signature algorithm. try this:
val encodeKey = Base64.encode(privateKey.toByteArray(), android.util.Base64.DEFAULT)
val jwt = Jwts.builder().setIssuer("firebase-adminsdk-kywht#...")
.setSubject("firebase-adminsdk-kywht#...")
.setAudience("https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit")
.setExpiration(calendar.time) //a java.util.Date
.setIssuedAt(Date())
.setId(UUID.randomUUID().toString())
.signWith(encodeKey, SignatureAlgorithm.RS512) //changed here
.compact()
Related
I am creating an app that works like an authenticator for the website logins, I have setup a server of https://www.strongkey.com/ and here is the samples I am following https://github.com/StrongKey/fido2/tree/master/sampleapps/java/sacl/mobile/android.
But I am not aware how to achieve this facility, What my application is doing is
Hitting the pre register api and getting the challenge to register
sample response
{"Response":{"rp":{"name":"FIDOServer","id":"fidoidqa.com"},"user":{"name":"devendra","id":"s5wXaholuoVwk86KQ0d_hmIxOkQPNS-bBBes8X4Cex8","displayName":"devendraLiapC"},"challenge":"COJ03Ch_6KDjlvnZ1jg_Qw","pubKeyCredParams":[{"type":"public-key","alg":-7},{"type":"public-key","alg":-35},{"type":"public-key","alg":-36},{"type":"public-key","alg":-8},{"type":"public-key","alg":-47},{"type":"public-key","alg":-257},{"type":"public-key","alg":-258},{"type":"public-key","alg":-259},{"type":"public-key","alg":-37},{"type":"public-key","alg":-38},{"type":"public-key","alg":-38}],"excludeCredentials":[{"type":"public-key","id":"NEVDOUQzNkMzMDBEM0U3MS1FNDczNTQ3QUVDRDQ1ODDRELTk1MEJFOTM2NTI5MEIxNjctMTIxNkNFQjY1ODIzQTI5OQ","alg":-7},{"type":"public-key","id":"MUUzMDY0RkNGQUZEOTM5Ni1FMzlFOUM2MkUwOTQE4NzcwLTA0NzUyMEFBREM0ODUwM0UtMEU4ODdFOEFCRjFCMDE3QQ","alg":-7},{"type":"public-key","id":"hhkXnYmUiu_bzLy5HPHJvZs6TQA-302jRdeLHBgpL40","alg":-257}],"attestation":"direct"}}
Then with this response, I am creating the preregisterchallenge,
var preregisterChallenge = PreregisterChallenge() val authenticatorSelectionCriteria = AuthenticatorSelectionCriteria() authenticatorSelectionCriteria.authenticatorAttachment = "Android" authenticatorSelectionCriteria.isRequireResidentKey = true authenticatorSelectionCriteria.userVerification = "required" val authSelectionJson = Gson().toJson(authenticatorSelectionCriteria) val myCustomArray: JsonArray = Gson().toJsonTree(userData.Response?.pubKeyCredParams).asJsonArray preregisterChallenge.apply { id = 100 uid = 1001 did = 1003 rpid = userData.Response?.rp?.id userid = "1001" username = "devendra" displayName = "devendra" challenge = userData.Response?.challenge authenticatorSelectionJSONObject = JSONObject(authSelectionJson) authenticatorSelection = authSelectionJson publicKeyCredentialParams = myCustomArray.toString() credParamsJSONArray = JSONArray(myCustomArray.toString()) }
And then doing like this
val publicKeyCredential = AuthenticatorMakeCredential.execute( ContextWrapper(context), preregisterChallenge, "fidoidqa.com" ) as PublicKeyCredential
I am getting the publickKeyCredential without any error
Now I want to attest this key with biometric humen presence with this public key, for example now user will touch the biometric to verify this public key and then I will call the register api.
How can I attest the public key credential with the biometric fingerprint and want a signed public key credential for future verification.
Hope this is well explained, Please help me in understanding the flow or process.
Thanks in advance
We are generating agora token from token server provided by agora but the token expires immmediately after the generation it throws DYNAMIC-KEY-EXPIRY with error code 109 and i have tried using onRequestToken() call back method provided in SDK below is the code snippet
override fun onRequestToken() {
//this will be called when the token expires
//so generate new token and renew the existing token
runOnUiThread {
regenerateToken()
}
}
and getting another token from server and renewing the token using mRtcEngine.renewToken(token)
we have contacted agora team regarding this but unable to find the issue the token generated works sometimes,we have two account one is test account and other is main account when we use the one credentials it works for a day or so and after we need to change the credentials for every 2 days
and the new generated token is expiring just after the generation
So if any one faced the same issue and any help regarding this is appreciated
When you generate the token, you can set the token expiration time in the request parameter. Here is a guide for token generation. https://docs.agora.io/en/Video/token_server?platform=Android
If you have set the expiration time but still having the issue, please let me know.
We are generating the token using agora token server and the time expiration is 3600
const { RtcTokenBuilder, RtmTokenBuilder, RtcRole, RtmRole } = require('agora-access-token');
const role = RtcRole.PUBLISHER;
const expirationTimeInSeconds = 3600
const currentTimestamp = Math.floor(Date.now() / 1000)
const privilegeExpiredTs = currentTimestamp + expirationTimeInSeconds
const generateAuthTokenToInititateCall = async (channel, cb) => {
const token = RtcTokenBuilder.buildTokenWithUid(appID, appCertificate, channel, 0, role, privilegeExpiredTs);
cb({ "token": token, "channel": channel })
}
this is the node js code snippet
Is anyone able to resolve this? This is occurring despite setting the expiration to 3600 seconds (1 hour from current time).
let me make this token generation for you very simple and also the later process.
*firstly how to generate token?
you need a backend server which provides you with token when you provide the server a channel name. no where you will be told that this backend server is not necessary. rather you can copy - paste the token generation code directly into the app in a form of directory.
*where is this token generation code?
https://github.com/AgoraIO/Tools/tree/master/DynamicKey/AgoraDynamicKey/java/src
this code is available for flutter also research a little bit.
*how to generate token using it?
once you have the all java files in your project you can use them to generate the token. here you can see a variable expirationTimeInSeconds, that will be the total time you want token to be active. rest all work leave it to the code it will do it for you.
package io.agora.sample;
import io.agora.media.RtcTokenBuilder;
import io.agora.media.RtcTokenBuilder.Role;
public class RtcTokenBuilderSample {
static String appId = "970CA35de60c44645bbae8a215061b33";
static String appCertificate = "5CFd2fd1755d40ecb72977518be15d3b";
static String channelName = "7d72365eb983485397e3e3f9d460bdda";
static String userAccount = "2082341273";
static int uid = 2082341273;
static int expirationTimeInSeconds = 3600;
public static void main(String[] args) throws Exception {
RtcTokenBuilder token = new RtcTokenBuilder();
int timestamp = (int)(System.currentTimeMillis() / 1000 + expirationTimeInSeconds);
String result = token.buildTokenWithUserAccount(appId, appCertificate,
channelName, userAccount, Role.Role_Publisher, timestamp);
System.out.println(result);
result = token.buildTokenWithUid(appId, appCertificate,
channelName, uid, Role.Role_Publisher, timestamp);
System.out.println(result);
}
}
result here is the generated token which is valid for 3600 seconds, that is 1hour.
How do i generate JWT token from android. I tried the following :
token = JWT.create().withClaim("email",username)
.sign(Algorithm.HMAC256("secret"));
System.out.println(" JWS token : "+ token);
But i got this exception :
java.lang.NoSuchMethodError: No static method encodeBase64URLSafeString([B)Ljava/lang/String; in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/ext.jar)
at com.auth0.jwt.JWTCreator.sign(JWTCreator.java:283)
at com.auth0.jwt.JWTCreator.access$100(JWTCreator.java:23)
at com.auth0.jwt.JWTCreator$Builder.sign(JWTCreator.java:264)
at se.stigasoft.netwrapper.NetCom.jwtWork(NetCom.java:321)
I tried other methos from some other library too.
String compactJws = Jwts.builder()
.setSubject("Joe")
.signWith(SignatureAlgorithm.HS256, "secret".getBytes())
.compact();
this one generates the token. But i dont know how to send my data like name,value pair that i used to send in the post method .
. Please help
To generate JWT token there is the way to generate:
1) add dependency in gradle
implementation 'io.jsonwebtoken:jjwt:0.7.0'
2) add the following code on the basis of the parameters.
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String jwt = Jwts.builder().claim("emailId","test123#gmail.com").claim("emailIdOTP", "123456")
.claim("phoneNo", "1111111111")
.signWith(SignatureAlgorithm.HS256, "secret".getBytes())
.compact();
Log.v("JWT : - ",jwt);
}
});
After much digging in the internet for last day I found the solution to this
String compactJws = Jwts.builder().claim("email",username).claim("password",password)
.signWith(SignatureAlgorithm.HS256, "secret".getBytes())
.compact()
this is the correct way to generate the token from the app side. So that the data is not sent in plain header.
In Kotlin Generate using this
val jws1 = Jwts.builder()
.setIssuer("issuer")
.setSubject("subject")
.signWith(SignatureAlgorithm.HS256, "key".toByteArray()).compact()
Log.d("SHUBH", "onCreate: $jws1")
Intermittently, GoogleTokenResponse.parseIdToken() has an NullPointerExpection because the token response does not contain an ID token. Without changing any code, sometimes there is an ID token, and sometimes there isn't. Note that GoogleTokenResponse.getAccessToken() always works.
With no change to any code whatsoever, the ID token will be missing from one minute to the next, even if the access token is always available.
How can I debug this? Where to look?
I get the server auth code using this in an Android client using Google Play Games API:
PendingResult<Games.GetServerAuthCodeResult> pendingResult =
Games.getGamesServerAuthCode(mGoogleApiClient, Constants.web_client_ID);
pendingResult.setResultCallback(new ResultCallback<Games.GetServerAuthCodeResult>() {
#Override
public void onResult(Games.GetServerAuthCodeResult getTokenResult) {
sendToServer(getTokenResult.getCode());
}
});
On the server side (Google Cloud Endpoints), I exchange the code for a token using this code:
try {
tokenResponse = new GoogleAuthorizationCodeTokenRequest(
transport,mJFactory,
"https://www.googleapis.com/oauth2/v4/token",
web_client_ID,web_client_secret,
authCode,
"")
.execute();
} ...
String accessToken = tokenResponse.getAccessToken();
GoogleIdToken idToken = null;
try {
idToken = tokenResponse.parseIdToken(); //-- FAILES HERE INTERMITTENTLY!!!!
} ...
Since it seems that Play Games Services does not guarantee an ID token using Games.getGamesServerAuthCode one should follow the directions in this post and get the ID token as it recommends:
Once you have the access token, you can now call
www.googleapis.com/games/v1/applications//verify/ using that
access token. Pass the auth token in a header as follows:
“Authorization: OAuth ” The response value will contain
the player ID for the user.
See this for a full example.
I am receiving an "Audience not allowed" warning in my google developers console logs when trying to make an authenticated request via Google Cloud Endpoints from an Android app.
Looking through the Endpoints source code, that corresponds to:
aud = parsed_token.get('aud')
cid = parsed_token.get('azp')
if aud != cid and aud not in audiences:
logging.warning('Audience not allowed: %s', aud)
My calling code in the android app:
public static final String WEB_CLIENT_ID = "web-client-id.apps.googleusercontent.com";
public static final String AUDIENCE = "server:client_id:" + WEB_CLIENT_ID;
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(
mContext,
AUDIENCE
);
Grapi.Builder builder = new Grapi.Builder(HTTP_TRANSPORT,
JSON_FACTORY, credential);
Grapi service = builder.build()
Where "web-client-id" is the alpha numeric client id generated in google developers console. This service is used to make authenticated calls.
This is also the same WEB_CLIENT_ID that is passed to the api decorator in my backend python code:
WEB_CLIENT_ID = 'web-client-id.apps.googleusercontent.com'
ANDROID_CLIENT_ID = 'android-client-id.apps.googleusercontent.com'
ANDROID_AUDIENCE = WEB_CLIENT_ID
grapi_client_ids = [ANDROID_CLIENT_ID,
WEB_CLIENT_ID,
endpoints.API_EXPLORER_CLIENT_ID]
grapi_audiences = [ANDROID_AUDIENCE]
#endpoints.api(name='grapi', version='v1',
allowed_client_ids=grapi_client_ids, audiences=grapi_audiences,
scopes=[endpoints.EMAIL_SCOPE])
It looks like all of this is causing endpoints.get_current_user() to return None, and my authenticated call to fail.
When I initialized my web client id and android client id variables in the python backend, I used backslashes for line continuation to conform with PEP8 (80 character line length) ie.
WEB_CLIENT_ID = 'web-client-id'\
'.apps.googleusercontent.com'
ANDROID_CLIENT_ID = 'android-client-id'\
'.apps.googleusercontent.com'
I am not sure why this was not read correctly, but when I used line continuation inside parenthesis it worked fine.
WEB_CLIENT_ID = ('web-client-id'
'.apps.googleusercontent.com')
ANDROID_CLIENT_ID = ('android-client-id'
'.apps.googleusercontent.com')