diff --git a/openlobby/mutations.py b/openlobby/mutations.py
index b9d542626707a691e44576642efa515df7a3cc41..a6b6086901506650a21b455437f303a01ceea5f5 100644
--- a/openlobby/mutations.py
+++ b/openlobby/mutations.py
@@ -3,6 +3,7 @@ from flask import g
 import graphene
 from graphene import relay
 from graphene.types.datetime import DateTime
+from graphql_relay import from_global_id
 from oic.oic import rndstr
 from oic.oic.message import AuthorizationResponse
 import time
@@ -13,9 +14,16 @@ from .auth import (
     get_session_expiration_time,
     create_access_token,
 )
-from .documents import UserDoc, LoginAttemptDoc, SessionDoc, ReportDoc
+from .documents import (
+    UserDoc,
+    LoginAttemptDoc,
+    SessionDoc,
+    ReportDoc,
+    OpenIdClientDoc,
+)
 from .openid import (
     init_client_for_uid,
+    init_client_for_shortcut,
     register_client,
     get_authorization_url,
     set_registration_info,
@@ -72,6 +80,59 @@ class Login(relay.ClientIDMutation):
         return Login(authorization_url=authorization_url)
 
 
+class LoginByShortcut(relay.ClientIDMutation):
+
+    class Input:
+        shortcut_id = relay.GlobalID(required=True)
+        redirect_uri = graphene.String(required=True)
+
+    authorization_url = graphene.String()
+
+    @classmethod
+    def mutate_and_get_payload(cls, root, info, **input):
+        shortcut_id = input['shortcut_id']
+        redirect_uri = input['redirect_uri']
+
+        type, id = from_global_id(shortcut_id)
+        openid_client_data = OpenIdClientDoc.get(id, using=info.context['es'],
+            index=info.context['index'])
+
+        # prepare OpenID client
+        client = init_client_for_shortcut(openid_client_data, redirect_uri)
+
+        # TODO
+        """
+        # prepare login attempt details
+        state = rndstr(32)
+        nonce = rndstr()
+        expiration = get_login_attempt_expiration_time()
+
+        # save login attempt into ES
+        data = {
+            'meta': {'id': client.client_id},
+            'state': state,
+            'nonce': nonce,
+            'client_id': client.client_id,
+            'client_secret': client.client_secret,
+            'openid_uid': openid_uid,
+            'redirect_uri': redirect_uri,
+            'expiration': expiration,
+        }
+        login_attempt = LoginAttemptDoc(**data)
+        login_attempt.save(using=info.context['es'], index=info.context['index'])
+
+        # already registered user?
+        user = UserDoc.get_by_openid_uid(openid_uid, **info.context)
+        is_new_user = user is None
+
+        # get OpenID authorization url
+        authorization_url = get_authorization_url(client, state, nonce, is_new_user)
+        """
+
+        authorization_url = 'http://localhost/foo'
+        return LoginByShortcut(authorization_url=authorization_url)
+
+
 class LoginRedirect(relay.ClientIDMutation):
 
     class Input:
@@ -184,6 +245,7 @@ class NewReport(relay.ClientIDMutation):
 
 class Mutation(graphene.ObjectType):
     login = Login.Field()
+    login_by_shortcut = LoginByShortcut.Field()
     login_redirect = LoginRedirect.Field()
     logout = Logout.Field()
     new_report = NewReport.Field()
diff --git a/openlobby/openid.py b/openlobby/openid.py
index 42522a71e12d51c0bb24e21af981b581546d54e1..f336e0af71b6468e5136eb559cb7bace2744ae61 100644
--- a/openlobby/openid.py
+++ b/openlobby/openid.py
@@ -1,5 +1,10 @@
 from oic.oic import Client
-from oic.oic.message import RegistrationResponse, ClaimsRequest, Claims
+from oic.oic.message import (
+    ProviderConfigurationResponse,
+    RegistrationResponse,
+    ClaimsRequest,
+    Claims,
+)
 from oic.utils.authn.client import CLIENT_AUTHN_METHOD
 
 from .settings import SITE_NAME
@@ -12,6 +17,19 @@ def init_client_for_uid(openid_uid):
     return client
 
 
+def init_client_for_shortcut(data, redirect_uri):
+    client = Client(client_authn_method=CLIENT_AUTHN_METHOD)
+    set_registration_info(client, data['client_id'], data['client_secret'], redirect_uri)
+    info = {
+        'issuer': data['issuer'],
+        'authorization_endpoint': data['authorization_endpoint'],
+        'token_endpoint': data['token_endpoint'],
+        'userinfo_endpoint': data['userinfo_endpoint'],
+    }
+    client.provider_info = ProviderConfigurationResponse(**info)
+    return client
+
+
 def register_client(client, redirect_uri):
     params = {
         'redirect_uris': [redirect_uri],
diff --git a/tests/snapshots/snap_test_management.py b/tests/snapshots/snap_test_management.py
index 6d030b28120260abb1958ec0e31fcf6ec114c5e5..28674d9096c3c1966df693b351fdd87c71015203 100644
--- a/tests/snapshots/snap_test_management.py
+++ b/tests/snapshots/snap_test_management.py
@@ -80,7 +80,7 @@ snapshots['test_create_index__check_mappings 1'] = {
                 'client_secret': {
                     'type': 'keyword'
                 },
-                'isShortcut': {
+                'is_shortcut': {
                     'type': 'boolean'
                 },
                 'issuer': {
@@ -89,9 +89,6 @@ snapshots['test_create_index__check_mappings 1'] = {
                 'name_x': {
                     'type': 'keyword'
                 },
-                'redirect_uri': {
-                    'type': 'keyword'
-                },
                 'token_endpoint': {
                     'type': 'keyword'
                 },
@@ -208,7 +205,7 @@ snapshots['test_init_alias 1'] = {
                 'client_secret': {
                     'type': 'keyword'
                 },
-                'isShortcut': {
+                'is_shortcut': {
                     'type': 'boolean'
                 },
                 'issuer': {
@@ -217,9 +214,6 @@ snapshots['test_init_alias 1'] = {
                 'name_x': {
                     'type': 'keyword'
                 },
-                'redirect_uri': {
-                    'type': 'keyword'
-                },
                 'token_endpoint': {
                     'type': 'keyword'
                 },
@@ -336,7 +330,7 @@ snapshots['test_reindex__check_new_index 1'] = {
                 'client_secret': {
                     'type': 'keyword'
                 },
-                'isShortcut': {
+                'is_shortcut': {
                     'type': 'boolean'
                 },
                 'issuer': {
@@ -345,9 +339,6 @@ snapshots['test_reindex__check_new_index 1'] = {
                 'name_x': {
                     'type': 'keyword'
                 },
-                'redirect_uri': {
-                    'type': 'keyword'
-                },
                 'token_endpoint': {
                     'type': 'keyword'
                 },
@@ -464,7 +455,7 @@ snapshots['test_init_documents 1'] = {
                 'client_secret': {
                     'type': 'keyword'
                 },
-                'isShortcut': {
+                'is_shortcut': {
                     'type': 'boolean'
                 },
                 'issuer': {
@@ -473,9 +464,6 @@ snapshots['test_init_documents 1'] = {
                 'name_x': {
                     'type': 'keyword'
                 },
-                'redirect_uri': {
-                    'type': 'keyword'
-                },
                 'token_endpoint': {
                     'type': 'keyword'
                 },