timApp.auth.oauth2 package#

Submodules#

timApp.auth.oauth2.models module#

class timApp.auth.oauth2.models.OAuth2AuthorizationCode(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model, authlib.integrations.sqla_oauth2.tokens_mixins.OAuth2AuthorizationCodeMixin

auth_time#
client_id#
code#
code_challenge#
code_challenge_method#
id#
nonce#
redirect_uri#
response_type#
scope#
user#
user_id#
class timApp.auth.oauth2.models.OAuth2Client(client_id: str, client_name: typing.Optional[str] = None, client_secret: str = '', redirect_urls: list[str] = <factory>, allowed_scopes: list[timApp.auth.oauth2.models.Scope] = <factory>, response_types: list[str] = <factory>, grant_types: list[str] = <factory>)[source]#

Bases: authlib.oauth2.rfc6749.models.ClientMixin

An application that is allowed to authenticate as a TIM user and use OAUTH-protected REST API.

allowed_scopes: list[timApp.auth.oauth2.models.Scope]#

Resource scopes that the client can ask for. Scopes are used to limit what REST API can be used.

check_client_secret(client_secret: str) bool[source]#

Check client_secret matching with the client. For instance, in the client table, the column is called client_secret:

def check_client_secret(self, client_secret):
    return self.client_secret == client_secret
Parameters

client_secret – A string of client secret

Returns

bool

check_endpoint_auth_method(method: str, endpoint: str) bool[source]#

Check if client support the given method for the given endpoint. There is a token_endpoint_auth_method defined via RFC7591. Developers MAY re-implement this method with:

def check_endpoint_auth_method(self, method, endpoint):
    if endpoint == 'token':
        # if client table has ``token_endpoint_auth_method``
        return self.token_endpoint_auth_method == method
    return True

Method values defined by this specification are:

  • “none”: The client is a public client as defined in OAuth 2.0,

    and does not have a client secret.

  • “client_secret_post”: The client uses the HTTP POST parameters

    as defined in OAuth 2.0

  • “client_secret_basic”: The client uses HTTP Basic as defined in

    OAuth 2.0

check_grant_type(grant_type: str) bool[source]#

Validate if the client can handle the given grant_type. There are four grant types defined by RFC6749:

  • authorization_code

  • implicit

  • client_credentials

  • password

For instance, there is a allowed_grant_types column in your client:

def check_grant_type(self, grant_type):
    return grant_type in self.grant_types
Parameters

grant_type – the requested grant_type string.

Returns

bool

check_redirect_uri(redirect_uri: str) bool[source]#

Validate redirect_uri parameter in Authorization Endpoints. For instance, in the client table, there is an allowed_redirect_uris column:

def check_redirect_uri(self, redirect_uri):
    return redirect_uri in self.allowed_redirect_uris
Parameters

redirect_uri – A URL string for redirecting.

Returns

bool

check_response_type(response_type: str) bool[source]#

Validate if the client can handle the given response_type. There are two response types defined by RFC6749: code and token. For instance, there is a allowed_response_types column in your client:

def check_response_type(self, response_type):
    return response_type in self.response_types
Parameters

response_type – the requested response_type string.

Returns

bool

client_id: str#

Unique identifier for the client.

client_name: str | None = None#

User-friendly client name

client_secret: str = ''#

Client secret that is used to allow OAUTH2 authentication.

get_allowed_scope(scope: str) str | None[source]#

A method to return a list of requested scopes which are supported by this client. For instance, there is a scope column:

def get_allowed_scope(self, scope):
    if not scope:
        return ''
    allowed = set(scope_to_list(self.scope))
    return list_to_scope([s for s in scope.split() if s in allowed])
Parameters

scope – the requested scope.

Returns

string of scope

get_client_id() str[source]#

A method to return client_id of the client. For instance, the value in database is saved in a column called client_id:

def get_client_id(self):
    return self.client_id
Returns

string

get_default_redirect_uri() str | None[source]#

A method to get client default redirect_uri. For instance, the database table for client has a column called default_redirect_uri:

def get_default_redirect_uri(self):
    return self.default_redirect_uri
Returns

A URL string

grant_types: list[str]#
What grant types the client can handle. Default values:
  • authorization_code

  • implicit

  • client_credentials

  • password

More custom grant types are allowed.

property name: str#
redirect_urls: list[str]#

List of valid URLs that TIM is allowed to redirect the user to upon successful authentication.

response_types: list[str]#

What response types the client can handle. In other words, tells TIM how to send user’s OAUTH2 token to the client. Allowed values: “code” and “token”.

token_endpoint_auth_method = 'client_secret_post'#

How the client authenticates itself with TIM. Allowed values: * “none”: The client is a public client as defined in OAuth 2.0,

and does not have a client secret.

  • “client_secret_post”: The client uses the HTTP POST parameters

    as defined in OAuth 2.0

  • “client_secret_basic”: The client uses HTTP Basic as defined in

    OAuth 2.0

class timApp.auth.oauth2.models.OAuth2Token(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model, authlib.integrations.sqla_oauth2.tokens_mixins.OAuth2TokenMixin

access_token#
access_token_revoked_at#
client_id#
expires_in#
id#
issued_at#
refresh_token#
refresh_token_revoked_at#
scope#
token_type#
user#
user_id#
class timApp.auth.oauth2.models.Scope(value)[source]#

Bases: enum.Enum

An enumeration.

profile = 'profile'#

timApp.auth.oauth2.oauth2 module#

class timApp.auth.oauth2.oauth2.AuthorizationCodeGrant(request, server)[source]#

Bases: authlib.oauth2.rfc6749.grants.authorization_code.AuthorizationCodeGrant

TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post']#

Allowed client auth methods for token endpoint

authenticate_user(authorization_code: timApp.auth.oauth2.models.OAuth2AuthorizationCode) timApp.user.user.User[source]#

Authenticate the user related to this authorization_code. Developers MUST implement this method in subclass, e.g.:

def authenticate_user(self, authorization_code):
    return User.query.get(authorization_code.user_id)
Parameters

authorization_code – AuthorizationCode object

Returns

user

delete_authorization_code(authorization_code: timApp.auth.oauth2.models.OAuth2AuthorizationCode) None[source]#

Delete authorization code from database or cache. Developers MUST implement it in subclass, e.g.:

def delete_authorization_code(self, authorization_code):
    authorization_code.delete()
Parameters

authorization_code – the instance of authorization_code

query_authorization_code(code: str, client: timApp.auth.oauth2.models.OAuth2Client) timApp.auth.oauth2.models.OAuth2AuthorizationCode | None[source]#

Get authorization_code from previously savings. Developers MUST implement it in subclass:

def query_authorization_code(self, code, client):
    return Authorization.get(code=code, client_id=client.client_id)
Parameters
  • code – a string represent the code.

  • client – client related to this code.

Returns

authorization_code object

save_authorization_code(code: str, request: authlib.oauth2.rfc6749.wrappers.OAuth2Request) timApp.auth.oauth2.models.OAuth2AuthorizationCode[source]#

Save authorization_code for later use. Developers MUST implement it in subclass. Here is an example:

def save_authorization_code(self, code, request):
    client = request.client
    item = AuthorizationCode(
        code=code,
        client_id=client.client_id,
        redirect_uri=request.redirect_uri,
        scope=request.scope,
        user_id=request.user.id,
    )
    item.save()
class timApp.auth.oauth2.oauth2.RefreshTokenGrant(request, server)[source]#

Bases: authlib.oauth2.rfc6749.grants.refresh_token.RefreshTokenGrant

INCLUDE_NEW_REFRESH_TOKEN = True#

The authorization server MAY issue a new refresh token

TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post']#

Allowed client auth methods for token endpoint

authenticate_refresh_token(refresh_token: str) timApp.auth.oauth2.models.OAuth2Token | None[source]#

Get token information with refresh_token string. Developers MUST implement this method in subclass:

def authenticate_refresh_token(self, refresh_token):
    token = Token.get(refresh_token=refresh_token)
    if token and not token.refresh_token_revoked:
        return token
Parameters

refresh_token – The refresh token issued to the client

Returns

token

authenticate_user(credential: timApp.auth.oauth2.models.OAuth2Token) timApp.user.user.User[source]#

Authenticate the user related to this credential. Developers MUST implement this method in subclass:

def authenticate_user(self, credential):
    return User.query.get(credential.user_id)
Parameters

credential – Token object

Returns

user

revoke_old_credential(credential: timApp.auth.oauth2.models.OAuth2Token) None[source]#

The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client. Developers MUST implement this method in subclass:

def revoke_old_credential(self, credential):
    credential.revoked = True
    credential.save()
Parameters

credential – Token object

timApp.auth.oauth2.oauth2.delete_expired_oauth2_tokens() None[source]#
timApp.auth.oauth2.oauth2.init_oauth(app: flask.app.Flask) None[source]#
timApp.auth.oauth2.oauth2.query_client(client_id: str) timApp.auth.oauth2.models.OAuth2Client[source]#
timApp.auth.oauth2.oauth2.require_oauth = <authlib.integrations.flask_oauth2.resource_protector.ResourceProtector object>#

Special decorator to request for permission scopes

timApp.auth.oauth2.routes module#

timApp.auth.oauth2.routes.authorize(confirm: bool) flask.wrappers.Response[source]#
timApp.auth.oauth2.routes.get_user_profile() flask.wrappers.Response[source]#
timApp.auth.oauth2.routes.issue_token() flask.wrappers.Response[source]#
timApp.auth.oauth2.routes.request_authorization() str | flask.wrappers.Response[source]#

Module contents#