Skip to content

feat(auth): implement Unsplash OAuth2 flow#34

Merged
lackary merged 6 commits intomainfrom
feat/33-implement-unsplash-oauth2-flow-setup-callback-page
Jan 17, 2026
Merged

feat(auth): implement Unsplash OAuth2 flow#34
lackary merged 6 commits intomainfrom
feat/33-implement-unsplash-oauth2-flow-setup-callback-page

Conversation

@lackary
Copy link
Owner

@lackary lackary commented Jan 14, 2026

Related Issues

Closes #33

Type of Change

Please check the main type of change this PR introduces. If there are multiple, please select the most significant one.

  • feat: New feature
  • fix: Bug fix
  • refactor: Code refactoring
  • docs: Documentation update
  • chore: Chore (e.g., updating dependencies, build tooling)
  • style: Style changes (e.g., formatting, no code logic changes)
  • test: Adding or modifying tests
  • other: Other: [Please briefly describe]

Description

This PR implements the full Unsplash OAuth2 login flow across all platforms and establishes a unified authentication architecture. [cite_start]It covers specific implementations for Android, iOS, JVM (Desktop), and Web[cite: 1].

Key Changes:

1. Core Authentication & Cross-Platform Implementation (feat(auth))

  • [cite_start]Unified Interface: Introduced AuthManager to abstract platform-specific login logic[cite: 2].
  • Platform Implementations:
    • [cite_start]Android/iOS: Uses system browser with custom scheme deep links (omnihub://auth/callback)[cite: 3].
    • [cite_start]JVM (Desktop): Starts a temporary local HTTP server on port 54321 to capture the auth code and displays a custom auth_success.html page[cite: 4].
    • [cite_start]Web: Manages URL redirection and captures auth codes from the window location state[cite: 5].
  • [cite_start]Architecture: Integrated authModule into Koin for dependency injection and updated GalleryViewModel to handle token exchange (ExchangeOAuthUseCase) and user profile fetching (GetMeUseCase)[cite: 9, 10, 23].

2. Deep Link Handling & Bug Fixes (fix(auth), feat(ios))

  • [cite_start]iOS Support: Updated Info.plist to register the URL scheme and added .onOpenURL handling in iOSApp.swift[cite: 12, 13, 14].
  • [cite_start]Resolved Race Condition: Refactored the authentication flow to use a Reactive approach instead of manual lifecycle checks[cite: 16].
    • [cite_start]Converted DeepLinkBuffer to use MutableStateFlow[cite: 17].
    • [cite_start]Updated GalleryViewModel to automatically collect deep link updates, removing the obsolete ON_START check logic[cite: 18, 20].

3. UI & Navigation Updates

  • [cite_start]Renamed the "Account" icon to "Settings" in the main navigation[cite: 8].
  • [cite_start]Added a login/profile button in the GalleryScreen top bar that toggles between an account icon, loading indicator, and user avatar[cite: 26].
  • [cite_start]Implemented logic to automatically navigate to the Gallery feature upon successful authentication[cite: 7].

4. Infrastructure (chore(cd), feat(auth web))

  • [cite_start]Static Callback Page: Added a Material 3-styled static site under site/auth/callback/ to handle OAuth redirection (supporting Desktop and Web flows)[cite: 33].
  • [cite_start]CI/CD: Created deploy_auth_web.yml to automatically deploy the static auth site to GitHub Pages[cite: 36].

How to test it?

Please follow these steps to verify the login flow on each platform:

Tested Platforms:

  • Android
  • iOS
  • Desktop (JVM)
  • Web (Wasm/JS)
  • Shared Logic (Unit Tests)

Test Details:

  • Android / iOS:

    1. Launch the App and click the Login icon in the top bar (or go to Settings).
    2. Verify that the system browser opens the Unsplash authorization page.
    3. After authorizing, verify that the browser redirects back to the App.
    4. Confirm the App shows a loading state and then switches to the user avatar.
  • Desktop (JVM):

    1. Click the login button.
    2. Verify the default browser opens the authorization page.
    3. After authorizing, confirm the browser shows the "Authentication Successful" page.
    4. Return to the App window and confirm successful login.
  • Web (Wasm/JS):

    1. Click the login button.
    2. Verify the page redirects to Unsplash.
    3. After authorizing, confirm it redirects back to the App URL and maintains the logged-in state.

Review Checklist

Before submitting this PR, please confirm the following:

  • My code follows the project's coding style guidelines.
  • I have added sufficient comments to my code, especially in complex areas.
  • I have updated the relevant documentation.
  • My changes don't introduce new bugs.
  • I have tested my code locally.

This commit introduces a static web page to handle OAuth redirection for both desktop and web platforms, along with a GitHub Actions workflow for automated deployment to GitHub Pages.

Key changes:
- **OAuth Callback Page**: Added a Material 3-styled static site under `site/auth/callback/` that extracts authorization codes from URL parameters.
- **Redirection Logic**:
    - Implemented deep linking (`omnihub://`) to redirect codes back to the desktop application.
    - Integrated `localStorage` persistence and automatic redirection for the Web (KMP Wasm) version.
- **CI/CD**: Created `deploy_auth_web.yml` to deploy the site to GitHub Pages on every push to `main` or pull request.
- **Project Configuration**: Updated existing CI workflows to ignore changes in the `site/` directory and the new deployment workflow to avoid redundant runs.
@lackary lackary self-assigned this Jan 14, 2026
@lackary lackary added the enhancement New feature or request label Jan 14, 2026
@lackary lackary linked an issue Jan 14, 2026 that may be closed by this pull request
10 tasks
This commit updates the GitHub Pages deployment workflow to use the correct directory for static web content.

Changes:
- **CI/CD**: Updated `upload-pages-artifact` path from `./web` to `./site` in `deploy_auth_web.yml`.
@github-actions
Copy link

github-actions bot commented Jan 14, 2026

⚠️ Test Deployment Active
The production URL has been updated with changes from this PR.
🌐 Live URL: https://lackary.github.io/omnihub/auth/callback/
Note: This will revert to main version only after a new deployment from the main branch.

This commit introduces the Unsplash OAuth login flow and deep link handling for the multiplatform project.

Key changes:
- **Authentication**: Added `DeepLinkBuffer` to capture and consume auth codes from platform-specific deep links. Integrated `ExchangeOAuthUseCase` and `GetMeUseCase` in `GalleryViewModel` to handle token exchange and user profile fetching.
- **Android Integration**: Updated `MainActivity` to handle incoming intents and pass deep link data to the common layer. Configured `AndroidManifest.xml` with `intent-filter` for the `omnihub://auth/callback` scheme and set `launchMode="singleTask"`.
- **UI Updates**:
    - Added a login/profile button in `GalleryScreen` top bar that toggles between an account icon, loading indicator, and user avatar.
    - Implemented `GallerySideEffect.OpenUrl` to launch the Unsplash authorization page via `LocalUriHandler`.
    - Integrated user profile state into `GalleryContract` and `GalleryUiState`.
- **Platform Configuration**: Added `getUnsplashSecretKey` expected/actual functions across Android, iOS, JVM, and Web platforms.
- **Environment**: Defined a centralized `AUTH_REDIRECT_URL` in the common utility package.
This commit refactors the authentication flow to use a reactive approach for handling deep links, replacing the manual lifecycle-based check.

Key changes:
- **DeepLinkBuffer**: Converted `pendingUrl` from a manual property to a `MutableStateFlow` (`deepLinkUrl`), allowing observers to react to incoming links. Added `consumeDeepLink` to clear the state.
- **GalleryViewModel**:
    - Added a coroutine to collect `deepLinkUrl` updates automatically.
    - Updated `handleAuthCallback` to accept the auth code directly from the stream.
    - Removed `GalleryIntent.CheckAuth` and its manual invocation logic.
- **GalleryScreen**: Removed the `LifecycleEventEffect` that previously triggered the auth check on `ON_START`.
- **GalleryContract**: Removed the obsolete `CheckAuth` intent.
This commit adds the necessary configuration and logic to handle deep links on iOS, enabling the application to intercept and process `omnihub://` URLs.

Key changes:
- **Configuration**: Updated `Info.plist` to register the `omnihub` URL scheme and `io.lackstudio.omnihub` identifier.
- **Deep Link Handling**: Added an `.onOpenURL` modifier in `iOSApp.swift` to intercept incoming URLs.
- **Integration**: Integrated with the shared Kotlin code by passing received URLs to `DeepLinkBuffer.shared`.
This commit introduces a unified authentication management system across Android, iOS, JVM (Desktop), and Web, enabling OAuth2 login via Unsplash.

Key changes:
- **Authentication Core**: Introduced `AuthManager` interface to abstract platform-specific login logic (Deep Links for mobile, Local Server for desktop, and Window Location for web).
- **Platform Implementations**:
    - **Android/iOS**: Uses system browser with custom scheme deep links (`omnihub://auth/callback`).
    - **JVM**: Starts a temporary local HTTP server on port 54321 to capture the auth code and displays a custom `auth_success.html` page.
    - **Web**: Manages URL redirection and captures auth codes from the browser's location state.
- **UI & Navigation**:
    - Renamed `AccountScreen` to `SettingsScreen` and updated navigation routes.
    - Updated `App` logic to automatically navigate to the Gallery feature if an auth code is detected in the `DeepLinkBuffer`.
    - Switched "Account" icon to "Settings" in the main navigation.
- **Architecture**:
    - Integrated `authModule` into Koin for dependency injection across all platforms.
    - Updated `GalleryViewModel` to use `AuthManager` for triggering logins and handling token exchange with dynamic redirect URIs.
- **Environment**: Added `AUTH_REMOTE_REDIRECT_URL` and `AUTH_LOCAL_REDIRECT_URL` to manage different callback targets.
@lackary lackary merged commit ae360f7 into main Jan 17, 2026
3 checks passed
@lackary lackary changed the title feat(auth): implement static OAuth callback page and deployment workflow feat(auth): implement Unsplash OAuth2 flow Jan 17, 2026
@github-actions
Copy link

🎉 This PR is included in version 0.13.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@lackary lackary deleted the feat/33-implement-unsplash-oauth2-flow-setup-callback-page branch January 18, 2026 01:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: implement Unsplash OAuth2 flow & setup callback page

1 participant