- login and get token from keycloak
- add token to http header, access protected resource
- auto refresh token
if you need phone support for keycloak , try my project: keycloak-phone-provider, this sample is base on: keycloak-phone-provider. this sample is android client, nothing stop you from implementing other java program.
copy keycloak-client to your project
Initialize:
accessTokenHolder=new KeycloakTokenHolder.Builder()
.host("www.XXX.com") // root address: like "www.XXX.com"
.realms("realms") // realms: config in your keycloak
.clientId("clientId") // clientId: config in your keycloak
.clientSecret("XXXX-XXXX-XXXX-XXXX-XXXXXXXXXX") //clientSecret : clientId: config in your keycloak
.storage(new SharedPreferencesStorage(getSharedPreferences("keycloak-sample",Context.MODE_PRIVATE),ACCESS_TOKEN_STORE_KEY)) // storage: you can custom for cc.coopersoft.accesstoken.keycloak.KeycloakTokenStorage
.build();
storage: you can custom storage from KeycloakTokenStorage, in my project ,i use tencent mmkv.
Login:
- Required auth code
KeycloakClient.accessTokenHolder().sendAuthenticationCode(binding.phoneNumber.getText().toString(),new CodeRequestCallback(){
@Override
public void onFailure(String phoneNumber,ErrorResult error){
binding.requestAuthCode.setEnabled(true);
runOnUiThread(()->toast("send code fail!"));
}
@Override
public void onSuccess(String phoneNumber,Result result){
Looper.prepare();
new CountDownTimer(result.getExpiresIn()*1000,1000){
@Override
public void onTick(long millisUntilFinished){
binding.requestAuthCode.setEnabled(false);
binding.requestAuthCode.setText("send("+millisUntilFinished/1000+")");
}
@Override
public void onFinish(){
binding.requestAuthCode.setEnabled(true);
binding.requestAuthCode.setText("resend");
}
}.start();
Looper.loop();
}
});
- Required token
KeycloakClient.accessTokenHolder().requireToken(PhoneCredential.builder().phone(phone).code(code).build(), new AuthenticationCallback() {
@Override
public void onFailure(ErrorResult error) {
runOnUiThread(() -> toast("login fail!"));
loading(false);
}
@Override
public void onSuccess() {
MainActivity.start(LoginActivity.this);
finish();
}
});
Access protected resource:
okHttpClientBuilder.addInterceptor(new AllAccessTokenInterceptor());
about Interceptor:
- AllAccessTokenInterceptor
- WhiteAccessTokenInterceptor
- you can custom Interceptor on AccessTokenInterceptor
in my project, I use Retrofit implement a dynamic Interceptor annotation like this:
@POST("pyramid/task/receive/{id}")
@RequireInterceptor({"accessToken"})
Observable<User> receive(@Path("id") int id);
Token auth refresh:
- auto refresh on token is expires.
- auto refresh on http required first return 401.
- refreshToke is expires, return 401.
verification phone number:
- Required verification code
KeycloakClient.accessTokenHolder().sendVerificationCode(binding.phoneNumber.getText().toString(), new CodeRequestCallback() {
@Override
public void onFailure(String phoneNumber, ErrorResult error) {
binding.requestAuthCode.setEnabled(true);
runOnUiThread(()-> toast("send code fail!"));
}
@Override
public void onSuccess(String phoneNumber, Result result) {
Looper.prepare();
new CountDownTimer(result.getExpiresIn() * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
binding.requestAuthCode.setEnabled(false);
binding.requestAuthCode.setText("send(" + millisUntilFinished / 1000 + ")");
}
@Override
public void onFinish() {
binding.requestAuthCode.setEnabled(true);
binding.requestAuthCode.setText("resend");
}
}.start();
Looper.loop();
}
});
- valid code
KeycloakClient.accessTokenHolder().verificationCode(binding.phoneNumber.getText().toString(), binding.authCode.getText().toString(), new VerificationCallback() {
@Override
public void onError(String phoneNumber, ErrorResult error) {
runOnUiThread(()-> toast("valid fail!" + error.getErrorDescription()));
}
@Override
public void onFailure(String phoneNumber) {
runOnUiThread(()-> toast("valid fail!"));
}
@Override
public void onSuccess(String phoneNumber) {
runOnUiThread(()-> toast("valid success"));
}
});
logout (clear token):
KeycloakClient.accessTokenHolder().clearToken();
other: look for PhoneSupportAccessTokenHolder.