Log In With Ansible

Ansible offers app and website developers a free and open platform that lets people sign up and log in with their Ansible account instead of inventing another password.

Benefits of Ansible Login

  • Higher conversion
    Users sign in with a few taps, boosting conversion and retention.

  • No passwords to keep
    Nothing to store, reset or leak — you never see a secret of theirs.

  • Direct communication channels
    You can reach your users within Ansible, with built-in push notification support.

  • Further integration
    You can deliver more services directly via the Bot API and Mini Apps.

Note: This document describes the Ansible Login library and the new OpenID Connect login flow.


Getting Started

Ansible offers a compact tool to quickly add Ansible login buttons to your interface. You can also directly access our library's JS API.

On mobile, use the standard OIDC redirect through the system browser — the same endpoints, no SDK required.

Alternatively, Ansible supports the standard OpenID Connect protocol. This allows you to integrate Ansible authentication into your application using any OIDC-compatible library or authentication platform (e.g., Keycloak, Authentik, Auth0 etc.).

Our implementation follows the standard Authorization Code Flow with PKCE support.

For an in-depth understanding of the general OIDC flow, please refer to the OpenID Foundation's Developer Guide.

TL;DR

  • Create an app in the developer dashboard — the @ansible_dev_bot bot, menu button opens https://id.ansible.su/app.
  • Register your URLs: the origin of the page carrying the button, and the redirect URI for OIDC. Pick up your client_id and client_secret there too.
  • Add the library https://id.ansible.su/widget.js to your page — or go through plain OIDC.
  • Validate the id_token on your server before trusting anything the browser sent.

Stuck on any of the steps above? Write to us and say which one.

Setting up a bot

Your app needs a card: the name and logo a user will see in the confirmation sheet. You create it in the developer dashboard — open the @ansible_dev_bot bot and press the menu button.

Use the logo from your site and the name that matches your address bar. People agree to hand over their data to someone they recognise; an unfamiliar name in that sheet is a reason to press Cancel.

Log in to example.com
This site will receive your name, username and profile photo.
Device iPhone 15 ProSafari 18
IP address 203.0.113.24Москва
This login attempt came from the device above.
Allow messages
The site's bot will be able to message you on Ansible.
Cancel Log in

Our client_id is not a bot id — it is a string like app_9f3ab21c issued by the dashboard. The client_secret is shown in the same place, to the owner of the app only.

Registering your Allowed URLs

An app card holds two lists, and they mean different things:

  • Origins — pages allowed to open the login window, e.g. https://example.com. No port, no path.
  • Redirect URIs — exact OIDC callback addresses, e.g. https://example.com/auth/callback. Compared byte for byte: a trailing slash makes it a different address.

Important: logins only work from pre-registered addresses. That is not paperwork — without the check, someone else’s site could walk a user through the real confirmation sheet and keep the result.

Using the Ansible Login library

Use the tool below to customize your button and get the HTML snippet for your website.

Alternatively, you can interact with the library using the following JS methods:

Available Methods

The library exposes one object, Ansible.

MethodDescription
Ansible.login(clientId, callback)Opens the login window and calls callback with the result. Both arguments are optional — without them the values come from the <script> tag attributes.

There is no separate init step: the library is ready as soon as it loads.

InitOptions

Configured through attributes on the same <script> tag.

AttributeTypeDescription
data-clientstringThe client_id from the dashboard. When present, the library inserts a button in place of the tag.
data-onauthstringThe name of a global function to call with the result. The name only: data-onauth="onAnsibleAuth", not onAnsibleAuth(data) — an expression will not run.
data-labelstringOptional. The button caption.
<script async src="https://id.ansible.su/widget.js"
        data-client="app_9f3ab21c"
        data-label="Войти через Ansible"
        data-onauth="onAnsibleAuth"></script>

<script>
  function onAnsibleAuth(data) {
    // data.jwt приходит только first-party клиентам.
    // Всё остальное проверяйте на своём сервере.
    fetch('/auth/ansible', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
  }
</script>

Callback Data

The function named by data-onauth receives one object.

FieldTypeDescription
statusstringconfirmed on success.
userobjectThe id and name of whoever logged in, plus auth_date.
hashstringHMAC-SHA256 over auth_date, id, name, photo_url, keyed with SHA-256 of your client_secret. Verify it server-side.
jwtstringFirst-party apps only. Not issued to ordinary clients.

🚨 Only the fields listed above are covered by the signature. Anything that arrives alongside and is not part of hash is browser-supplied: there is nothing to check it against, so do not make decisions on it.

OpenID Connect

If you are using an OIDC-compatible library or identity broker, you can use the standard configuration values below.

Discovery Document URL

https://id.ansible.su/.well-known/openid-configuration

Client Configuration

Parameter Value
Client ID The Client ID from the developer dashboard
Client Secret The Client Secret from the developer dashboard
Response Type code
PKCE Required (S256)

Available Scopes

We declare two scopes. openid is required.

ScopeDescriptionClaims returned
openidRequired. The user identifier and the auth timestamp.sub, iss, aud, iat, exp, auth_time
profileThe display name.name, picture

Login with Ansible returns no phone number and no email — we have no such scope. If you need a verified number, ask the user for it yourself: quietly handing someone’s phone to a third-party site is not a fair price for a convenient login.

picture currently comes back as an empty string: profile photos do not reach the token yet. The claim is declared and will not disappear — rely on the key, not on the value.

User Data Structure

All the data arrives directly in the ID token. A decoded id_token looks like this:

{
  "iss": "https://id.ansible.su",
  "aud": "app_9f3ab21c",
  "sub": "1234567890",
  "iat": 1753900000,
  "exp": 1753903600,
  "auth_time": 1753900000,
  "name": "Мария",
  "picture": "",
  "nonce": "n-0S6_WzA2Mj"
}

sub is a string even when it holds a number. Store it as text — not every identifier survives a parse to integer.

There is a /userinfo endpoint; it returns sub, name and picture for a Bearer token, and nothing beyond what the id_token already carries. OIDC libraries can skip it.

Manual Implementation

If you are integrating the OIDC flow manually without a library, use the endpoints and flow details below.

Endpoints

  • Discovery: https://id.ansible.su/.well-known/openid-configuration
  • Authorization: https://id.ansible.su/authorize
  • Token: https://id.ansible.su/token
  • UserInfo: https://id.ansible.su/userinfo
  • Keys (JWKS): https://id.ansible.su/.well-known/jwks.json

Configuring a library or an identity broker (Keycloak, Authentik, Auth0)? The discovery URL is all you need — it picks up the rest.

Initiate Authorization

Send the user to the authorization endpoint in their browser.

GET https://id.ansible.su/authorize?
    client_id=<YOUR_CLIENT_ID>&
    redirect_uri=<YOUR_CALLBACK_URL>&
    response_type=code&
    scope=openid%20profile&
    state=<RANDOM_STRING>&
    code_challenge=<PKCE_CHALLENGE>&
    code_challenge_method=S256
  • client_id — the app_… string from the dashboard.
  • redirect_uri — exactly as registered on the app card.
  • state — a random string from your backend, to prevent CSRF.
  • code_challengebase64url(sha256(verifier)).

PKCE is required. Discovery advertises both S256 and plain, but a code exchange without a code_verifier currently fails with invalid_grant. Use S256 — it both works and is the right choice.

Exchange Code for Tokens

Once the user confirms, they return to your redirect_uri with a code parameter. Exchange it from your server, not from the browser.

POST https://id.ansible.su/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=<AUTHORIZATION_CODE>&
redirect_uri=<YOUR_CALLBACK_URL>&
client_id=<YOUR_CLIENT_ID>&
client_secret=<YOUR_CLIENT_SECRET>&
code_verifier=<PKCE_VERIFIER>

Client authentication is client_secret_post: the secret goes in the request body. Our server does not read HTTP Basic, so an Authorization header buys you nothing here.

Response:

{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "id_token": "eyJhbGciOiJSUzI1NiIs...",
  "scope": "openid profile"
}

The code is single-use and lives 10 minutes. No refresh_token is issued: an access_token lasts an hour, after which the user signs in again.

Validating ID Tokens

The id_token is a signed JWT. Before trusting what is inside, validate the signature:

  1. Fetch the keys from https://id.ansible.su/.well-known/jwks.json — by the kid in the token header.
  2. Verify the signature with RS256.
  3. Check the claims: iss is https://id.ansible.su, aud is your client_id, exp is not in the past, and nonce matches the one you sent.

There is one key today and it is not rotated, but the header already carries a kid. Select by it rather than taking the first key in the list — otherwise the first rotation breaks logins, and for everyone at once.

Signing algorithm

Tokens are signed with RS256, using an RSA-2048 key. No other algorithm is offered.

AlgorithmStatus
RS256The only one. Works with every OIDC library out of the box.

JWKS always holds exactly one active key. Choosing the algorithm per application is not supported.