PlusAuth OpenID Connect Library for Android
Android OpenId Connect library that can be used with any OIDC provider for easy to use authentication. We value developer time and effort, so we developed a dead simple zero config library that any one could easily integrate in a minute, while allowing veterans of authentication to customize everything to their needs.
Table of Contents
- Requirements
- Installation
- OIDC Provider Configuration
- Configuration
- Login
- Logout
- Using the Tokens
- Advanced Usage
- Example App
- Acknowledgements
- License
Requirements
PlusAuth OpenID Connect Library for Android supports Android Apis starting from 16(Jelly Bean) and above.
Installation
Add the library dependency to your build.gradle file:
implementation 'com.plusauth:android:0.1.10'This library uses and requires Java 8 support. Check out Android Documentation to learn more.
To enable, add the following following to your build.gradle file
android {
...
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// For Kotlin projects
kotlinOptions {
jvmTarget = "1.8"
}
}OIDC Provider Configuration
To use the library you must have a OIDC provider account. In this part we will use PlusAuth as an example.
- Create a Plusauth account and a tenant at PlusAuth Dashboard
- Navigate to
Clientstab and create a client of typeNative Application. - Go to details page of the client that you've just created and set the following fields as:
- Redirect Uris:
${your-application-id}:/callback - Post Logout Redirect Uris:
${your-application-id}:/callback
Done! Note your 'Client Id' and 'domain' for library configuration later.
Configuration
The entry point of the library is the OIDC object. OIDC object can be created by using the OIDCBuilder.
OIDC oidc = new OIDCBuilder(
context,
"your-client-id",
"your-oidc-domain")
.build();Login
By default library uses Authorization Code + PKCE flow for maximum security.
Library wraps all steps of auth flow in to a single call:
oidc.login(context, new LoginRequest(), new AuthenticationCallback() {
@Override
public void onSuccess(Credentials credentials) {
runOnUiThread(()->{
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Login failed", e);
}
});OIDC will open a browser custom tab(if supported) or browser page showing them your OIDC login page and users will be returned back to the app after they complete the login.
After successful response credentials will be locally stored to skip the OIDC flow at next login.
If there are valid credentials in Storage they will be returned instead, skipping OIDC exchange.
This call is asychronous and requires a callback. If you want to do ui related work in callback you must use Activity.runOnUiThread to switch back to main thread since login request is executed in a seperate thread.
Logout
Logout call is similar to login:
oidc.logout(this, new LogoutRequest(), new VoidCallback() {
@Override
public void onSuccess(Void aVoid) {
runOnUiThread(()->{
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Logout failed", e);
});OIDC will momenrarily open a browser custom tab(if supported) or page of OIDC logout page and users will be immediately returned back to the app. This clears users browser session.
After successful response credentials will be locally removed. This completes the two step logout process.
If there aren't valid credentials in Storage request will fail.
If you have them, you can revoke your refresh tokens using the Revoke tokens method from Api.
This call is asychronous and requires a callback. If you want to do ui related work in callback you must use Activity.runOnUiThread to switch back to main thread since login request is executed in a seperate thread.
Api
Api class wraps common OIDC calls and provides easy to use interface. Requests can be called both asynchronously or synchronously.
No arg method overloads uses provided storage instance
to get required tokens.
Obtain api instance:
Api api = oidc.getApi();If you create the api instance manually, make sure to set credentials manager so the no arg overloads can be used, otherwise you will get null pointer errors(also could occur if storage does not have credentials).
Get User Info
Get User Profile information using /userinfo endpoint:
api.userInfo().call(new PACallback<UserProfile, AuthenticationException>() {
@Override
public void onSuccess(UserProfile userProfile) {
runOnUiThread(() -> {
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Could not get profile", e);
}
});Exchange auth token for credentials
Sends auth token to /token endpoint of the provider in exchange for credentials.
api.token("your-auth-token").call(new AuthenticationCallback() {
@Override
public void onSuccess(Credentials credentials) {
runOnUiThread(() -> {
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Could exchange auth token", e);
}
});Renew Credential with a Refresh Token
Renew your credentials using a refresh token. Note that 'offline_access' scope is required to get a refresh refresh token at login, which is added by default.
api.renewAuth().call(new AuthenticationCallback() {
@Override
public void onSuccess(Credentials credentials) {
runOnUiThread(() -> {
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Could not renew auth", e);
}
});Revoke a Token
Revoke a token using the revokeToken method. No arg overload only revokes the stored refresh token:
api.revokeToken().call(new VoidCallback() {
@Override
public void onSuccess(Void aVoid) {
runOnUiThread(() -> {
// do ui related work
});
}
@Override
public void onFailure(AuthenticationException e) {
Log.e("TAG", "Could not revoke token", e);
}
});Advance Usage
Storage
By default library uses SharedPreferences in Private mode(can only be accessed by this application) for persistence. You are free to implement the Storage interface with your preferred storage backend.
Configure your Storage:
OIDC oidc = new OIDCBuilder(
context,
"your-client-id",
"your-oidc-domain")
.setStorage(new Storage() {
@Override
public void write(@NonNull String s, @Nullable String s1) {
}
@Override
public void delete(@NonNull String s) {
}
@Override
public String read(@NonNull String s) {
return null;
}
})
.build();Encryption
By default library does not use any encryption when storing credentials. You are free to implement the Encryptor interface with your preferred encryption method. We provide AESEncryptor class for 256 bit AES GCM implementation which can be used from Android Api 23 and up.
Configure your Encryptor:
OIDC oidc = new OIDCBuilder(
context,
"your-client-id",
"your-oidc-domain")
.setEncryptor(new Encryptor() {
@Override
public String encrypt(String s) {
return null;
}
@Override
public String decrypt(String s) {
return null;
}
})
.build();Example App
We built a very simple app demonstrating login/logout and fetching user info. Check it out here.
Acknowledgements
Design of this library was inspired by awesome OSS libraries such as AppAuth.
If you have used OIDC with any Android library, you might have felt overwhelmed. We did too. That is why we built PlusAuth OIDC Library For Android. We hope to lower the entry barrier for OIDC complexity so that all developers could enjoy benefits that it brings.
License
This project is licensed under the MIT license. See the LICENSE file for more info.