@startuml oauth_pkce_social_sign_in_sequence
title OAuth Social Sign-In with PKCE and State Verification

actor "Browser Client" as Client
participant "OAuthPlugin\n/sign-in/social" as OAuthStart
participant "Verification store\n(oauth:{state})" as VerifyStore
participant "OAuth Provider" as Provider
participant "OAuthPlugin\n/callback/{provider}" as OAuthCallback
participant "DatabaseAdapter\nusers + accounts" as DB
participant "SessionManager" as SessionManager

Client -> OAuthStart: POST /sign-in/social { provider }
OAuthStart -> OAuthStart: generate_pkce() + random state
OAuthStart -> VerifyStore: create_verification(oauth:{state}, callback_url, code_verifier, link_user_id, scopes)
VerifyStore --> OAuthStart: stored
OAuthStart --> Client: 200 { url, redirect:true }

Client -> Provider: GET authorize URL (state + PKCE challenge)
Provider --> Client: auth consent + redirect with code/state
Client -> OAuthCallback: GET /callback/{provider}?code=...&state=...

OAuthCallback -> VerifyStore: get_verification_by_identifier(oauth:{state})
VerifyStore --> OAuthCallback: state payload
OAuthCallback -> VerifyStore: delete_verification(...)

OAuthCallback -> Provider: token exchange (code + code_verifier)
Provider --> OAuthCallback: access_token + refresh_token + id_token
OAuthCallback -> Provider: userinfo(access_token)
Provider --> OAuthCallback: mapped user info

alt account exists for provider/account_id
    OAuthCallback -> DB: update_account(tokens, expires, scope) [config-dependent]
    OAuthCallback -> DB: get_user_by_id(account.user_id)
else account missing
    OAuthCallback -> DB: get_user_by_email(...)
    alt existing user and linking allowed
        OAuthCallback -> DB: optional update_user_info_on_link
    else new user
        OAuthCallback -> DB: create_user(...)
    end
    OAuthCallback -> DB: create_account(provider/account/tokens)
end

OAuthCallback -> SessionManager: create_session(user, ip, user_agent)
SessionManager --> OAuthCallback: session token
OAuthCallback --> Client: 200 { token, user } + Set-Cookie session token

@enduml

