Class: CollavreLinear::AuthController
- Inherits:
-
ApplicationController
- Object
- ApplicationController
- ApplicationController
- CollavreLinear::AuthController
- Defined in:
- app/controllers/collavre_linear/auth_controller.rb
Instance Method Summary collapse
-
#callback ⇒ Object
GET /linear/auth/callback?code=...&state=...
-
#setup ⇒ Object
GET /linear/auth/setup?creative_id=...
-
#store_creative ⇒ Object
POST /linear/auth/store_creative Persist creative_id and generate a CSRF state token in the session, then redirect the popup window straight to Linear's OAuth screen.
Instance Method Details
#callback ⇒ Object
GET /linear/auth/callback?code=...&state=... Exchange the authorization code, create/update the Account, capture the OAuth app actor id via the GraphQL viewer query.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'app/controllers/collavre_linear/auth_controller.rb', line 13 def callback expected_state = session.delete(:linear_oauth_state) unless params[:state].present? && params[:state] == expected_state redirect_to collavre.creatives_path, alert: I18n.t("collavre_linear.auth.invalid_state", default: "Invalid OAuth state. Please try connecting again.") return end tokens = OAuthTokenService.exchange(params[:code]) # Build a temporary account so we can call the viewer query temp_account = CollavreLinear::Account.new( access_token: tokens[:access_token] ) client = CollavreLinear::Client.new(temp_account) viewer = client.viewer_and_app_actor # Never reassign a Linear identity already owned by another Collavre user # (that would steal their account + project links). Bind by the CURRENT # user instead (user_id is unique — one Linear account per user), so a # reconnect with a different Linear UID updates in place rather than # violating the unique index. if CollavreLinear::Account.where(linear_uid: viewer[:user_id]) .where.not(user_id: Current.user.id).exists? redirect_to collavre.creatives_path, alert: I18n.t("collavre_linear.auth.already_linked_other") return end account = CollavreLinear::Account.find_or_initialize_by( user_id: Current.user.id ) account.linear_uid = viewer[:user_id] account.access_token = tokens[:access_token] account.refresh_token = tokens[:refresh_token] account.token_expires_at = Time.current + tokens[:expires_in].to_i.seconds if tokens[:expires_in] account.app_actor_id = viewer[:app_actor_id] account.workspace_id = viewer[:organization_id] account.save! creative_id = session.delete(:linear_creative_id) if creative_id.present? # Redirect to the MOUNTED path (/linear/auth/setup). The engine is # detached, so we fold its mount prefix in explicitly via `script_name:` # — the bare engine-internal /auth/setup would 404 in the popup. redirect_to linear_engine.setup_auth_path( creative_id: creative_id, script_name: CollavreLinear::Engine::MOUNT_PATH ) else redirect_to collavre.creatives_path, notice: I18n.t("collavre_linear.auth.connected", default: "Linear connected.") end end |
#setup ⇒ Object
GET /linear/auth/setup?creative_id=... Setup wizard entry point — mirrors the collavre_github pattern.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'app/controllers/collavre_linear/auth_controller.rb', line 71 def setup @creative_id = params[:creative_id] unless @creative_id.present? render plain: I18n.t("collavre_linear.integration.missing_creative", default: "creative_id is required"), status: :bad_request return end @creative = Collavre::Creative.find_by(id: @creative_id) unless @creative render plain: I18n.t("collavre_linear.integration.missing_creative", default: "Creative not found"), status: :not_found return end unless @creative.(Current.user, :admin) render plain: I18n.t("collavre_linear.errors.forbidden", default: "Access denied"), status: :forbidden return end render layout: false end |
#store_creative ⇒ Object
POST /linear/auth/store_creative Persist creative_id and generate a CSRF state token in the session, then redirect the popup window straight to Linear's OAuth screen. The form POSTs into a popup with no JS handler, so returning JSON here would just render raw JSON in the popup and never start OAuth — a 303 redirect makes the popup follow through to Linear.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'app/controllers/collavre_linear/auth_controller.rb', line 105 def store_creative missing = OAuthTokenService.missing_config if missing.any? render plain: I18n.t("collavre_linear.auth.oauth_config_missing", keys: missing.join(", ")), status: :service_unavailable return end session[:linear_creative_id] = params[:creative_id] state = SecureRandom.hex(24) session[:linear_oauth_state] = state = OAuthTokenService.(state: state, creative_id: params[:creative_id]) redirect_to , allow_other_host: true, status: :see_other end |