Skip to content

Sign-in

auth.login() opens the provider's sign-in page in the browser, receives the answer and keeps the tokens. It uses the Authorization Code flow with PKCE, so the APK carries no client secret.

Microsoft (Entra ID)

from apkpy_lib import Screen, label, button, auth, run

login = Screen(id="login")
home = Screen(id="home")
hello = label("", id="hello", screen=home)


def sign_in():
    auth.login("microsoft", "YOUR_APPLICATION_CLIENT_ID",
               tenant="contoso.onmicrosoft.com", then=home)


button("Sign in with Microsoft", id="go", screen=login, command=sign_in)
run(start_screen=login)

tenant= is your directory: its domain or its id. Leave it out for common (work and personal accounts); organizations accepts only work accounts, consumers only personal ones.

The default scopes are openid profile email offline_access User.Read. offline_access is what lets the session last longer than the first token.

Register the app

In the Microsoft Entra admin center, under App registrations, choose New registration:

  1. Under Authentication, add the platform Mobile and desktop applications.
  2. Add the redirect URI apkpy://auth for the phone.
  3. Add http://localhost/callback for the Previewer. Microsoft ignores the port of a localhost address, so the Previewer's port can change without a new registration.
  4. Copy the Application (client) ID into auth.login().

The app is a public client: there is no secret to create.

Any OpenID Connect provider

Okta, Auth0, Keycloak and most company sign-ins publish their addresses at /.well-known/openid-configuration. Give ApkPy the issuer and it reads the rest:

auth.login(issuer="https://login.example.com", client_id="YOUR_CLIENT_ID", then=home)

The default scopes are openid profile email offline_access. Pass scopes= to change them. Register apkpy://auth (phone) and the Previewer's loopback address (http://127.0.0.1:8888/callback) with the provider.

Google, GitHub, Spotify

auth.login("google", "YOUR_CLIENT_ID", then=home)
auth.login("spotify", "YOUR_CLIENT_ID", scopes=["user-read-email"], then=home)

For any other OAuth provider, pass auth_url= and token_url= yourself.

After signing in

def show():
    c = auth.claims()
    hello.set_value("Hello, " + c["name"])

token = auth.token()          # for an Authorization: Bearer header
signed_in = auth.is_logged_in()
auth.logout()
  • auth.claims() is the sign-in's ID token as a dict: name, email, and for Microsoft the user's oid and the directory's tid. It is {} for providers that send no ID token (GitHub, Spotify).
  • auth.user(on_result=...) asks the provider for the profile over the network.
  • then= opens only after a sign-in that worked. If the person cancels, or the answer is not one this app asked for, the app stays where it was.

How the tokens are kept

  • On the phone, the tokens are encrypted with a key from the Android Keystore that never leaves the device. They stay out of Android's backups and phone-to-phone transfers, so on a new phone the person signs in again.
  • A token close to expiring is renewed with the refresh token, without asking the person again. If the provider refuses the renewal (the session was revoked, the password changed), the app is signed out and auth.is_logged_in() answers False.
  • In the Previewer, the tokens are kept in ~/.apkpy/auth.json on your computer.

The check that each answer belongs to the sign-in the app started (the OAuth state) is done for you.