Skip to content

jamesonwilliams/kosmos

Repository files navigation

Release Build

Kosmos the Ghost

kosmos

Kosmos is a lightweight Android library for authorizing your app's users to access resources in your AWS account.

AWS IAM, Amazon Cognito

Access to AWS resources is traditionally controlled through AWS' Identity & Access Management service. However, your app's users like to sign-in with their own username and password, not with your organization's IAM credentials. That's one of the problems Amazon Cognito solves.

Cognito enables users to register accounts and sign into your app. User accounts are mapped to roles/policies which you define. Registered users can signIn(...) to obtain credentials. Credentials can be OAuth2 tokens, or temporary IAM credentials, allowing access to specific resources in your account.

Kosmos' Design

Under the hood, Kosmos includes a few barebones REST clients to communicate with Amazon Cognito endpoints. It also provides a high-level client for performing common application use cases (signin, account registration, etc.)

The library handles a number of low-level details for you, such as exchanging challenges via the Secure Remote Password (SRP) Protocol, securely storing credentials, and automatically refreshing expired credentials.

How to Use It

Setup Backend Resources

Firstly, you need to setup an Amazon Cognito User Pool. Go to the Amazon Cognito Console, and create a User Pool. Be sure to add an app and make note of its ID and seret.

Next, create an Amazon Cognito Identity Pool. You can do so through the Amazon Cognito Console, here. When prompted to add provider information, enter the ID of the User Pool you created above, as well as the app client ID, from above.

Installation

The library is available from JitPack.

To start using it, add the following to your root-level build.gradle:

allprojects {
    repositories {
        // Add this line:
        maven { url 'https://jitpack.io' }
    }
}

And take a dependency on Kosmos in your application's build.gradle:

dependencies {
    implementation 'com.github.jamesonwilliams:kosmos:0.1'
}

Instantiate an instance of Auth:

val auth = Auth(
    context = applicationContext,
    userPoolId = 'your cognito user pool id',
    identityPoolId = 'your cognito identity pool id',
    clientId = 'your cognito client app id',
    clientSecret = 'your cognito client app secret'
)

User registration flow

Firstly, collect the user's desired email and password, and call registerUser(...). Amazon Cognito will send a verification email to the user.

lifcycleScope.launch(Dispatchers.IO) {
    when (auth.registerUser(email, pass, mapOf("email" to email))) {
        is ConfirmedRegistration -> { /* goto sign in */ }
        is UnconfirmedRegistration -> { /* prompt user for code */ }
    }
}

When it does, prompt the user to enter the verification code in your UI, and pass it to confirmRegistration(...).

lifecycleScope.launch(Dispatchers.IO) {
    auth.confirmSignIn(username, code)
}

If the code matches, registration succeeds and the user can proceed to sign in.

Signing in

To sign in, simply call signIn(...):

lifecycleScope.launch(Dispatchers.IO) {
    auth.signIn(username, password)
}

Accessing tokens and credentials

Once a user has signed in, OAuth tokens are available through tokens(). A ValidTokens instance contains an OIDC ID token and an OAuth2 access token.

// Get OAuth2 access token and OIDC ID token
lifecycleScope.launch(Dispatchers.IO) {
    when (val tokens = auth.tokens()) {
        is ValidTokens -> {
            val accessToken = tokens.accessToken
            val idToken = tokens.idToken
        }
    }
}

Session-scoped AWS credentials are also available, through session(). An AuthenticatedSession will contain an AWS IAM access key, secret key, and session token.

// Call session() to get AWS IAM session credentials
// You can use these to call AWS services
lifecycleScope.launch(Dispatchers.IO) {
    when (val session = auth.session()) {
        is AuthenticatedSession -> {
            val accessKey = session.credentials.accessKey
            val secretKey = session.credentials.secretKey
            val sessionToken = session.credentials.sessionToken
        }
        else -> { /* goto sign in flow */ }
    }
}

Demo App

Checkout the demo app, included in this repo.

It shows user sign-up:

Code confirmation and sign-in: