5 changed files with 137 additions and 0 deletions
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true |
||||
|
||||
module WellKnown |
||||
class OauthMetadataController < ActionController::Base # rubocop:disable Rails/ApplicationController |
||||
include CacheConcern |
||||
|
||||
# Prevent `active_model_serializer`'s `ActionController::Serialization` from calling `current_user` |
||||
# and thus re-issuing session cookies |
||||
serialization_scope nil |
||||
|
||||
def show |
||||
# Due to this document potentially changing between Mastodon versions (as |
||||
# new OAuth scopes are added), we don't use expires_in to cache upstream, |
||||
# instead just caching in the rails cache: |
||||
render_with_cache( |
||||
json: ::OauthMetadataPresenter.new, |
||||
serializer: ::OauthMetadataSerializer, |
||||
content_type: 'application/json', |
||||
expires_in: 15.minutes |
||||
) |
||||
end |
||||
end |
||||
end |
||||
@ -0,0 +1,67 @@
|
||||
# frozen_string_literal: true |
||||
|
||||
class OauthMetadataPresenter < ActiveModelSerializers::Model |
||||
include RoutingHelper |
||||
|
||||
attributes :issuer, :authorization_endpoint, :token_endpoint, |
||||
:revocation_endpoint, :scopes_supported, |
||||
:response_types_supported, :response_modes_supported, |
||||
:grant_types_supported, :token_endpoint_auth_methods_supported, |
||||
:service_documentation, :app_registration_endpoint |
||||
|
||||
def issuer |
||||
root_url |
||||
end |
||||
|
||||
def service_documentation |
||||
'https://docs.joinmastodon.org/' |
||||
end |
||||
|
||||
def authorization_endpoint |
||||
oauth_authorization_url |
||||
end |
||||
|
||||
def token_endpoint |
||||
oauth_token_url |
||||
end |
||||
|
||||
# As the api_v1_apps route doesn't technically conform to the specification |
||||
# for OAuth 2.0 Dynamic Client Registration defined in RFC 7591 we use a |
||||
# non-standard property for now to indicate the mastodon specific registration |
||||
# endpoint. See: https://datatracker.ietf.org/doc/html/rfc7591 |
||||
def app_registration_endpoint |
||||
api_v1_apps_url |
||||
end |
||||
|
||||
def revocation_endpoint |
||||
oauth_revoke_url |
||||
end |
||||
|
||||
def scopes_supported |
||||
doorkeeper.scopes |
||||
end |
||||
|
||||
def response_types_supported |
||||
doorkeeper.authorization_response_types |
||||
end |
||||
|
||||
def response_modes_supported |
||||
doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq |
||||
end |
||||
|
||||
def grant_types_supported |
||||
grant_types_supported = doorkeeper.grant_flows.dup |
||||
grant_types_supported << 'refresh_token' if doorkeeper.refresh_token_enabled? |
||||
grant_types_supported |
||||
end |
||||
|
||||
def token_endpoint_auth_methods_supported |
||||
%w(client_secret_basic client_secret_post) |
||||
end |
||||
|
||||
private |
||||
|
||||
def doorkeeper |
||||
@doorkeeper ||= Doorkeeper.configuration |
||||
end |
||||
end |
||||
@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true |
||||
|
||||
class OauthMetadataSerializer < ActiveModel::Serializer |
||||
attributes :issuer, :authorization_endpoint, :token_endpoint, |
||||
:revocation_endpoint, :scopes_supported, |
||||
:response_types_supported, :response_modes_supported, |
||||
:grant_types_supported, :token_endpoint_auth_methods_supported, |
||||
:service_documentation, :app_registration_endpoint |
||||
end |
||||
@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true |
||||
|
||||
require 'rails_helper' |
||||
|
||||
describe 'The /.well-known/oauth-authorization-server request' do |
||||
let(:protocol) { ENV.fetch('LOCAL_HTTPS', true) ? :https : :http } |
||||
|
||||
before do |
||||
host! ENV.fetch('LOCAL_DOMAIN') |
||||
end |
||||
|
||||
it 'returns http success with valid JSON response' do |
||||
get '/.well-known/oauth-authorization-server' |
||||
|
||||
expect(response) |
||||
.to have_http_status(200) |
||||
.and have_attributes( |
||||
media_type: 'application/json' |
||||
) |
||||
|
||||
grant_types_supported = Doorkeeper.configuration.grant_flows.dup |
||||
grant_types_supported << 'refresh_token' if Doorkeeper.configuration.refresh_token_enabled? |
||||
|
||||
expect(body_as_json).to include( |
||||
issuer: root_url(protocol: protocol), |
||||
service_documentation: 'https://docs.joinmastodon.org/', |
||||
authorization_endpoint: oauth_authorization_url(protocol: protocol), |
||||
token_endpoint: oauth_token_url(protocol: protocol), |
||||
revocation_endpoint: oauth_revoke_url(protocol: protocol), |
||||
scopes_supported: Doorkeeper.configuration.scopes.map(&:to_s), |
||||
response_types_supported: Doorkeeper.configuration.authorization_response_types, |
||||
grant_types_supported: grant_types_supported, |
||||
# non-standard extension: |
||||
app_registration_endpoint: api_v1_apps_url(protocol: protocol) |
||||
) |
||||
end |
||||
end |
||||
Loading…
Reference in new issue