diff --git a/Gemfile b/Gemfile
index 67cf53b1acb21b05089c95591e16e7da7ec574a5..2e4c4122ed2cda1635948a45ecd9a3ebedf89dbd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -149,6 +149,9 @@ gem "omniauth-twitter",   "1.2.1"
 gem "twitter",            "5.15.0"
 gem "omniauth-wordpress", "0.2.2"
 
+# OpenID Connect
+gem "openid_connect"
+
 # Serializers
 
 gem "active_model_serializers", "0.9.3"
diff --git a/app/controllers/openid/authorizations_controller.rb b/app/controllers/openid/authorizations_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f1d407043353d12d49a02ac2bcedbbc631933572
--- /dev/null
+++ b/app/controllers/openid/authorizations_controller.rb
@@ -0,0 +1,47 @@
+class AuthorizationsController < ApplicationController
+  rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
+    @error = e
+    logger.info e.backtrace[0,10].join("\n")
+    render :error, status: e.status
+  end
+
+  def new
+    call_authorization_endpoint
+  end
+
+  def create
+    call_authorization_endpoint :allow_approval, params[:approve]
+  end
+
+  private
+
+  def call_authorization_endpoint(allow_approval = false, approved = false)
+    endpoint = AuthorizationEndpoint.new allow_approval, approved
+    rack_response = *endpoint.call(request.env)
+    @client, @response_type, @redirect_uri, @scopes, @_request_, @request_uri, @request_object = *[
+        endpoint.client, endpoint.response_type, endpoint.redirect_uri, endpoint.scopes, endpoint._request_, endpoint.request_uri, endpoint.request_object
+    ]
+    require_authentication
+    if (
+    !allow_approval &&
+        (max_age = @request_object.try(:id_token).try(:max_age)) &&
+        current_account.last_logged_in_at < max_age.seconds.ago
+    )
+      flash[:notice] = 'Exceeded Max Age, Login Again'
+      unauthenticate!
+      require_authentication
+    end
+    respond_as_rack_app *rack_response
+  end
+
+  def respond_as_rack_app(status, header, response)
+    ["WWW-Authenticate"].each do |key|
+      headers[key] = header[key] if header[key].present?
+    end
+    if response.redirect?
+      redirect_to header['Location']
+    else
+      render :new
+    end
+  end
+end
diff --git a/app/controllers/openid/connect_controller.rb b/app/controllers/openid/connect_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c552988a6d2d29bc636b326a356773ebc9a4d75b
--- /dev/null
+++ b/app/controllers/openid/connect_controller.rb
@@ -0,0 +1,4 @@
+class ConnectController < ApplicationController
+  def show
+  end
+end
diff --git a/app/controllers/openid/discovery_controller.rb b/app/controllers/openid/discovery_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1b70dcae09dc585da0c702176bd8be3ca02a323a
--- /dev/null
+++ b/app/controllers/openid/discovery_controller.rb
@@ -0,0 +1,45 @@
+class DiscoveryController < ApplicationController
+  def show
+    case params[:id]
+      when 'webfinger'
+        webfinger_discovery
+      when 'openid-configuration'
+        openid_configuration
+      else
+        raise HttpError::NotFound
+    end
+  end
+
+  private
+
+  def webfinger_discovery
+    jrd = {
+      links: [{
+        rel: OpenIDConnect::Discovery::Provider::Issuer::REL_VALUE,
+        href: "http://0.0.0.0:3000"
+      }]
+    }
+    jrd[:subject] = params[:resource] if params[:resource].present?
+    render json: jrd, content_type: "application/jrd+json"
+  end
+
+  def openid_configuration
+    config = OpenIDConnect::Discovery::Provider::Config::Response.new(
+      issuer: "http://0.0.0.0:3000",
+      authorization_endpoint: "#{authorizations_url}/new",
+      token_endpoint: access_tokens_url,
+      userinfo_endpoint: user_info_url,
+      jwks_uri: "#{authorizations_url}/jwks.json",
+      registration_endpoint: "http://0.0.0.0:3000/connect",
+      scopes_supported: "iss",
+      response_types_supported: "Client.available_response_types",
+      grant_types_supported: "Client.available_grant_types",
+      request_object_signing_alg_values_supported: [:HS256, :HS384, :HS512],
+      subject_types_supported: ['public', 'pairwise'],
+      id_token_signing_alg_values_supported: [:RS256],
+      token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],
+      claims_supported: ['sub', 'iss', 'name', 'email']
+    )
+    render json: config
+  end
+end
diff --git a/config/routes.rb b/config/routes.rb
index 4babaf6301c8c4204da91c3e96c393b104309150..147212a985da847f3204af159d5ff06fd1e0721f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -240,4 +240,13 @@ Diaspora::Application.routes.draw do
 
   # Startpage
   root :to => 'home#show'
+
+  #OpenID Connect & OAuth
+  resource :openid do
+    resources :authorizations, only: [:new, :create]
+    match 'connect', to: 'connect#show', via: [:get, :post]
+    match '.well-known/:id', to: 'discovery#show' , :via => [:get, :post]
+    match 'user_info',       to: 'user#show', :via => [:get, :post]
+    post 'access_tokens', to: proc { |env| TokenEndpoint.new.call(env) }
+  end
 end
diff --git a/db/schema.rb b/db/schema.rb
index 6a526fe46ece8d14da4451d32485bbd2b1fb0dec..59f51d5d1d4a87fa5dd26d48419f0919a51b5852 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -419,7 +419,7 @@ ActiveRecord::Schema.define(version: 20151003142048) do
     t.string   "location",         limit: 255
     t.string   "full_name",        limit: 70
     t.boolean  "nsfw",                           default: false
-    t.boolean  "public_details",               default: false
+    t.boolean  "public_details",                 default: false
   end
 
   add_index "profiles", ["full_name", "searchable"], name: "index_profiles_on_full_name_and_searchable", using: :btree
diff --git a/lib/openid_connect/authorization_endpoint.rb b/lib/openid_connect/authorization_endpoint.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0d8b021c3997051f7d81fe9cdaaf2bcd553bc9bc
--- /dev/null
+++ b/lib/openid_connect/authorization_endpoint.rb
@@ -0,0 +1,82 @@
+class AuthorizationEndpoint
+  attr_accessor :app, :account, :client, :redirect_uri, :response_type, :scopes, :_request_, :request_uri, :request_object
+  delegate :call, to: :app
+
+  def initialize(allow_approval = false, approved = false)
+    @account = nil
+    @app = Rack::OAuth2::Server::Authorize.new do |req, res|
+      @client = nil # Find the client
+      res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.redirect_uris)
+      if res.protocol_params_location == :fragment && req.nonce.blank?
+        req.invalid_request! 'nonce required'
+      end
+      @scopes = req.scope.inject([]) do |_scopes_, scope|
+        _scopes_ << Scope.find_by_name(scope) or req.invalid_scope! "Unknown scope: #{scope}"
+      end
+      @request_object = if (@_request_ = req.request).present?
+                          OpenIDConnect::RequestObject.decode req.request, nil # @client.secret
+                        elsif (@request_uri = req.request_uri).present?
+                          OpenIDConnect::RequestObject.fetch req.request_uri, nil # @client.secret
+                        end
+      if Client.available_response_types.include? Array(req.response_type).collect(&:to_s).join(' ')
+        if allow_approval
+          if approved
+            approved! req, res
+          else
+            req.access_denied!
+          end
+        else
+          @response_type = req.response_type
+        end
+      else
+        req.unsupported_response_type!
+      end
+    end
+  end
+
+  def approved!(req, res)
+    response_types = Array(req.response_type)
+    if response_types.include? :code
+      authorization = account.authorizations.create!(client: @client, redirect_uri: res.redirect_uri, nonce: req.nonce)
+      authorization.scopes << scopes
+      if @request_object
+        authorization.create_authorization_request_object!(
+            request_object: RequestObject.new(
+                jwt_string: @request_object.to_jwt(@client.secret, :HS256)
+            )
+        )
+      end
+      res.code = authorization.code
+    end
+    if response_types.include? :token
+      access_token = account.access_tokens.create!(client: @client)
+      access_token.scopes << scopes
+      if @request_object
+        access_token.create_access_token_request_object!(
+            request_object: RequestObject.new(
+                jwt_string: @request_object.to_jwt(@client.secret, :HS256)
+            )
+        )
+      end
+      res.access_token = access_token.to_bearer_token
+    end
+    if response_types.include? :id_token
+      _id_token_ = account.id_tokens.create!(
+          client: @client,
+          nonce: req.nonce
+      )
+      if @request_object
+        _id_token_.create_id_token_request_object!(
+            request_object: RequestObject.new(
+                jwt_string: @request_object.to_jwt(@client.secret, :HS256)
+            )
+        )
+      end
+      res.id_token = _id_token_.to_jwt(
+          code: (res.respond_to?(:code) ? res.code : nil),
+          access_token: (res.respond_to?(:access_token) ? res.access_token : nil)
+      )
+    end
+    res.approve!
+  end
+end
\ No newline at end of file
diff --git a/lib/openid_connect/token_endpoint.rb b/lib/openid_connect/token_endpoint.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c2198497229c4fc903cc64382b3010c16307aee8
--- /dev/null
+++ b/lib/openid_connect/token_endpoint.rb
@@ -0,0 +1,29 @@
+class TokenEndpoint
+  attr_accessor :app
+  delegate :call, to: :app
+
+  def initialize
+    @app = Rack::OAuth2::Server::Token.new do |req, res|
+      client = Client.find_by_identifier(req.client_id) || req.invalid_client!
+      client.secret == req.client_secret || req.invalid_client!
+      case req.grant_type
+        when :client_credentials
+          res.access_token = client.access_tokens.create!.to_bearer_token
+        when :authorization_code
+          authorization = client.authorizations.valid.find_by_code(req.code)
+          req.invalid_grant! if authorization.blank? || !authorization.valid_redirect_uri?(req.redirect_uri)
+          access_token = authorization.access_token
+          res.access_token = access_token.to_bearer_token
+          if access_token.accessible?(Scope::OPENID)
+            res.id_token = access_token.account.id_tokens.create!(
+                client: access_token.client,
+                nonce: authorization.nonce,
+                request_object: authorization.request_object
+            ).to_response_object.to_jwt IdToken.config[:private_key]
+          end
+        else
+          req.unsupported_grant_type!
+      end
+    end
+  end
+end
\ No newline at end of file