Skip to content

Wildcard Photos

The Wildcard Photos integration downloads a user’s Northwestern Wildcard ID card photo from the Directory Search API and stores it in S3. Photos are served to the application via time-limited presigned URLs.

This feature is disabled by default and can be enabled with a single environment variable.

  1. Photo sync triggered

    When a user is fetched from the directory, FindOrUpdateUserFromDirectory dispatches a DownloadWildcardPhotoJob if WILDCARD_PHOTO_SYNC_ENABLED is true. During SSO sign-in the job is queued. It runs synchronously only when an administrator creates a user or uses Refresh from Directory in the administration panel.

  2. LDAP photo retrieval

    The job calls DirectorySearch::lookupByNetId() with 3 retries and 100ms delay. The jpegPhoto attribute in the LDAP response contains the base64-encoded photo.

  3. S3 storage

    The decoded photo is written to wildcard-photos/{netid}.jpg on the s3 disk. The user record is updated with the wildcard_photo_s3_key and wildcard_photo_last_synced_at timestamp. If the lookup fails, no photo is found, or the upload fails, the existing key and timestamp are left unchanged.

  4. Serving photos

    The photo is the user’s Filament avatar: User::getFilamentAvatarUrl() returns the photo route. WildcardPhotoController generates a 30-minute presigned S3 URL and returns a redirect response. If no photo is stored, or the viewer fails the view gate, it redirects to the default profile image instead.


The photo endpoint requires authentication and checks Gate::allows('view', $user) before returning the photo URL. This ensures users can only access photos they are authorized to see.

The response includes Cache-Control: private, max-age=1800 (30 minutes) to match the presigned URL lifetime.


MethodURINameNotes
GET/users/{user}/wildcard-photousers.wildcard-photoOnly registered when feature is enabled

.env
WILDCARD_PHOTO_SYNC_ENABLED=true

When disabled, the photo route is not registered and the DownloadWildcardPhotoJob is not dispatched during login. The feature is completely inert.