Skip to content

Logo and picture

This page helps you show a client’s logo or a user’s profile picture in your app.

The auth server serves both images, with no sign-in and no token:

  • GET /client/logo/{clientIdentifier}, the logo an administrator uploaded for a client.
  • GET /userinfo/picture/{subject}, a user’s profile picture. It’s the URL in the user’s picture claim.
  1. Sign the user in with the profile scope, and read the picture claim from the ID token or /userinfo. It’s there only when the user has a picture:

    {
    "sub": "2bd9ff17-7cb1-4c11-8d6d-6a3e1a0f5a6b",
    "picture": "https://auth.example.com/userinfo/picture/2bd9ff17-7cb1-4c11-8d6d-6a3e1a0f5a6b"
    }
  2. Use the URL as it is, in an <img> tag:

    <img src="https://auth.example.com/userinfo/picture/2bd9ff17-7cb1-4c11-8d6d-6a3e1a0f5a6b" alt="">

A client’s logo works the same way: <img src="https://auth.example.com/client/logo/my-app">.

GET /client/logo/{clientIdentifier} answers with the client’s logo, under the image type it was uploaded as, such as image/png.

The logo is public whatever the client’s state. It’s served while the client is disabled, and while Show logo is off: that switch decides whether the sign-in screens show the logo, not whether anyone may fetch it. The admin console’s Logo tab previews it through this same URL.

The answer carries an ETag and Cache-Control: public, max-age=300, must-revalidate, so a browser or a proxy keeps it for five minutes and then asks again. A request with an If-None-Match naming the current ETag, or *, is answered 304 Not Modified with no body. A HEAD request is answered as a GET is, with the same headers and no body, here and for the profile picture.

A client that doesn’t exist, or has no logo, is answered 404 Not Found. The identifier is matched exactly, case included.

GET /userinfo/picture/{subject} answers with the picture of the user whose subject is in the path, under the image type it was uploaded as.

It’s served whatever the user’s state, a disabled user included, with Cache-Control: no-store, no-cache, must-revalidate and no ETag, so a browser fetches it again every time and a user who replaces their picture never keeps showing the old one.

A subject that names no user, or a user with no picture, is answered 404 Not Found.

An administrator uploads a client’s logo on the client’s Logo tab, and a user’s picture on the user’s Picture tab. Users upload their own under Picture on their account pages in the admin console. See Clients and Users and groups.

In the admin console, both take a JPEG, PNG, GIF or WebP file of up to 3 MiB, and let you crop it before it’s uploaded. A picture is uploaded as a 512x512 JPEG. A logo keeps its shape, scaled down to at most 512 pixels on its longest side, and its type, but for a GIF, which is uploaded as PNG.

The Admin API checks the image itself: JPEG, PNG, GIF or WebP, read from the file’s content rather than its name, from 10x10 to 512x512 pixels, and up to GOIABADA_PROFILE_PICTURE_MAX_SIZE_BYTES, 3 MiB by default, for logos too. Raising that setting doesn’t raise the admin console’s 3 MiB.

Both endpoints work in an <img> tag from any site, which needs nothing more. They send no CORS headers, so JavaScript on another origin can’t read the image’s bytes with fetch.