OAuth 2.0 · OpenID Connect

Add “Sign in with Ismilink” to your site.

Your users sign in with their Ismilink account and you get their profile securely. The flow follows the standards: any OAuth or OpenID Connect library works.

How it works

Ismilink uses the Authorization Code flow, recommended for websites and mobile apps.

  1. Register your application
    In your Ismilink space, Developers tab: name, logo and allowed redirect URLs. You get a Client ID and a Client secret.
  2. Redirect to Ismilink
    Your button sends the user to /oauth/authorize. They sign in and accept the requested permissions.
  3. Receive a code
    Ismilink sends the user back to your redirect URL with a single-use code valid for 10 minutes.
  4. Exchange it server-side
    Your server exchanges the code for an access token, a refresh token and a signed id_token.

Endpoints

EndpointURL
OpenID discoveryhttps://mylinkis.com/.well-known/openid-configuration
Authorizationhttps://mylinkis.com/oauth/authorize
Tokenshttps://mylinkis.com/oauth/token
User profilehttps://mylinkis.com/oauth/userinfo
Revocationhttps://mylinkis.com/oauth/revoke
Public keys (JWKS)https://mylinkis.com/oauth/jwks

Permissions (scopes)

ScopeGrants access to
openidA unique identifier to sign you in (OpenID Connect).
profileName, username, photo, language and links to your public pages.
emailThe email address of your Ismilink account.
linksThe public links on your page (excluding locked links).
portfolioTitle, bio and city shown on your published portfolio.

1. Redirect the user

Build the authorization URL with your Client ID, a registered redirect URL, the permissions you need and a random state value you will check on return.

GET /oauth/authorize
https://mylinkis.com/oauth/authorize
  ?response_type=code
  &client_id=al_xxxxxxxxxxxx
  &redirect_uri=https://ooyee.net/auth/ismilink/callback
  &scope=openid%20profile%20email
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_SHA256_VERIFIER
  &code_challenge_method=S256

If the user accepts, they come back to your redirect URL with ?code=…&state=…. If they decline, you receive ?error=access_denied.

2. Exchange the code

From your server only (never put the secret in the browser), exchange the code for tokens. Client authentication uses Basic auth or the request body.

Node.js — server-side
const res = await fetch('https://mylinkis.com/oauth/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    Authorization: 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'),
  },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code,
    redirect_uri: 'https://ooyee.net/auth/ismilink/callback',
    code_verifier, // if you used PKCE
  }),
});
const { access_token, refresh_token, id_token, expires_in } = await res.json();
PHP
$ch = curl_init('https://mylinkis.com/oauth/token');
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_USERPWD => CLIENT_ID . ':' . CLIENT_SECRET,
  CURLOPT_POSTFIELDS => http_build_query([
    'grant_type' => 'authorization_code',
    'code' => $_GET['code'],
    'redirect_uri' => 'https://ooyee.net/auth/ismilink/callback',
  ]),
]);
$tokens = json_decode(curl_exec($ch), true);

3. Read the profile

Call /oauth/userinfo with the header Authorization: Bearer <access_token>. Returned fields depend on the granted permissions.

GET /oauth/userinfo — response
{
  "sub": "42",
  "name": "Sara Benali",
  "preferred_username": "sara",
  "picture": "https://mylinkis.com/uploads/…",
  "profile": "https://mylinkis.com/p/sara",
  "website": "https://mylinkis.com/@sara",
  "locale": "fr",
  "email": "sara@example.com",
  "email_verified": false
}

Use the “sub” field as the user's stable identifier: it never changes, even if the user edits their name or email.

PKCE (public apps)

For an app without a server (mobile, SPA), tick “Public application”: no secret is used and PKCE becomes mandatory. Generate a code_verifier, send its SHA-256 hash as code_challenge, then pass the code_verifier during the exchange.

JavaScript
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = base64url(new Uint8Array(digest));

Refresh and revoke

The access token expires after one hour. Use the refresh token to get a new one: it is replaced on every use (rotation). To sign a user out, revoke their tokens.

POST /oauth/token
grant_type=refresh_token&refresh_token=alrt_…
# revoke a token (sign out)
POST /oauth/revoke   token=alat_…

The official button

Use this button so your users recognise Ismilink at a glance. Keep the label “Sign in with Ismilink” and a height of at least 44 px.

HTML + CSS
<a class="ismilink-btn" href="/auth/ismilink">
  <img src="https://mylinkis.com/img/logo.png" alt="" width="22" height="22">
  Sign in with Ismilink
</a>
<style>
.ismilink-btn{display:inline-flex;align-items:center;gap:12px;min-height:48px;padding:0 20px;
  border-radius:14px;background:linear-gradient(135deg,#3d5afe,#7c3aed);color:#fff;
  font:600 16px/1 system-ui,sans-serif;text-decoration:none;
  box-shadow:0 10px 30px -10px rgba(124,58,237,.8),inset 0 1px 0 rgba(255,255,255,.25)}
.ismilink-btn:hover{filter:brightness(1.08)}
.ismilink-btn:focus-visible{outline:3px solid #6d28d9;outline-offset:2px}
</style>