diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index b01bc8c0d..58d101bc2 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -46,7 +46,7 @@ module Authentication end def resume_session - if session = find_session_by_cookie || find_or_start_session_by_bearer_token + if session = find_session_by_cookie || find_session_by_bearer_token set_current_session session end end @@ -55,7 +55,7 @@ module Authentication Session.find_signed(cookies.signed[:session_token]) end - def find_or_start_session_by_bearer_token + def find_session_by_bearer_token if request_authorized_by_bearer_token? Identity::AccessToken.find_by(token: authorization_bearer_token)&.session end diff --git a/app/models/identity/access_token.rb b/app/models/identity/access_token.rb index c5e3d6705..1702de78a 100644 --- a/app/models/identity/access_token.rb +++ b/app/models/identity/access_token.rb @@ -1,17 +1,14 @@ class Identity::AccessToken < ApplicationRecord belongs_to :identity + belongs_to :session has_secure_token enum :permission, %w[ read write ].index_by(&:itself), default: :read - def session - identity.sessions.find_or_create_by! user_agent: session_user_agent - end + before_validation :build_session, on: :create private - # Overload the user_agent identification for access token session reuse. - # This allows us to easily reuse a single session record per access token. - def session_user_agent - "access-token-#{id}" + def build_session + self.session = identity.sessions.build(user_agent: "Access Token") end end diff --git a/db/migrate/20251201132341_create_identity_access_tokens.rb b/db/migrate/20251201132341_create_identity_access_tokens.rb index 0e455104d..2b7648bf0 100644 --- a/db/migrate/20251201132341_create_identity_access_tokens.rb +++ b/db/migrate/20251201132341_create_identity_access_tokens.rb @@ -2,6 +2,7 @@ class CreateIdentityAccessTokens < ActiveRecord::Migration[8.2] def change create_table :identity_access_tokens, id: :uuid do |t| t.uuid :identity_id, null: false + t.uuid :session_id, null: false t.string :token t.string :permission t.text :description diff --git a/db/schema.rb b/db/schema.rb index 85a8f8064..9fe6d65a6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -326,6 +326,7 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_05_010536) do t.text "description" t.uuid "identity_id", null: false t.string "permission" + t.uuid "session_id", null: false t.string "token" t.datetime "updated_at", null: false t.index ["identity_id"], name: "index_access_token_on_identity_id" diff --git a/db/schema_sqlite.rb b/db/schema_sqlite.rb index e2f65dccc..8121ea7ef 100644 --- a/db/schema_sqlite.rb +++ b/db/schema_sqlite.rb @@ -326,6 +326,7 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_05_010536) do t.text "description", limit: 65535 t.uuid "identity_id", null: false t.string "permission", limit: 255 + t.uuid "session_id", null: false t.string "token", limit: 255 t.datetime "updated_at", null: false t.index ["identity_id"], name: "index_access_token_on_identity_id" diff --git a/test/fixtures/identity/access_tokens.yml b/test/fixtures/identity/access_tokens.yml index cfbbb6248..83e3d5542 100644 --- a/test/fixtures/identity/access_tokens.yml +++ b/test/fixtures/identity/access_tokens.yml @@ -1,11 +1,13 @@ jasons_api_token: identity: jason + session: jason_api token: 018cf1425682700098f24f0799e3fe20 description: My Superscript permission: read davids_api_token: identity: david + session: david_api token: x18cf1425682700098f24f0799e3fe20 description: My Superscript permission: write diff --git a/test/fixtures/sessions.yml b/test/fixtures/sessions.yml index 56fc614a5..56b6fb7c7 100644 --- a/test/fixtures/sessions.yml +++ b/test/fixtures/sessions.yml @@ -1,6 +1,9 @@ david: identity: david +david_api: + identity: david + kevin: identity: kevin @@ -12,3 +15,6 @@ jason: mike: identity: mike + +jason_api: + identity: jason diff --git a/test/models/identity/access_token_test.rb b/test/models/identity/access_token_test.rb index 49f1c57ce..daa236b49 100644 --- a/test/models/identity/access_token_test.rb +++ b/test/models/identity/access_token_test.rb @@ -1,13 +1,8 @@ require "test_helper" class Identity::AccessTokenTest < ActiveSupport::TestCase - test "only one session at the time" do - assert_changes -> { Session.count }, +1 do - identity_access_tokens(:jasons_api_token).session - end - - assert_no_changes -> { Session.count } do - identity_access_tokens(:jasons_api_token).session - end + test "new access token comes with a session" do + access_token = identities(:david).access_tokens.create! + assert_equal "Access Token", identities(:david).sessions.last.user_agent end end