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:
- Under Authentication, add the platform Mobile and desktop applications.
- Add the redirect URI
apkpy://authfor the phone. - Add
http://localhost/callbackfor the Previewer. Microsoft ignores the port of alocalhostaddress, so the Previewer's port can change without a new registration. - 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:
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'soidand the directory'stid. 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()answersFalse. - In the Previewer, the tokens are kept in
~/.apkpy/auth.jsonon your computer.
The check that each answer belongs to the sign-in the app started (the OAuth state) is done for
you.