oqtant.util.auth API documentation

# oqtant.util.auth

View Source

      1# Copyright 2023 Infleqtion
      2#
      3# Licensed under the Apache License, Version 2.0 (the "License");
      4# you may not use this file except in compliance with the License.
      5# You may obtain a copy of the License at
      6#
      7#     https://www.apache.org/licenses/LICENSE-2.0
      8#
      9# Unless required by applicable law or agreed to in writing, software
     10# distributed under the License is distributed on an "AS IS" BASIS,
     11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12# See the License for the specific language governing permissions and
     13# limitations under the License.
     14
     15import base64
     16import hashlib
     17import os
     18import webbrowser
     19from multiprocessing import Queue
     20
     21import requests
     22import uvicorn
     23from fastapi import APIRouter, FastAPI, Request
     24from fastapi.responses import RedirectResponse
     25
     26from oqtant.settings import Settings
     27from oqtant.util.server import ThreadServer
     28
     29settings = Settings()
     30
     31app = FastAPI(title="Login API", openapi_url="/openapi.json")
     32router = APIRouter()
     33
     34
     35def generate_random(length: int) -> str:
     36    return base64.urlsafe_b64encode(os.urandom(length)).decode("utf-8").replace("=", "")
     37
     38
     39verifier = generate_random(80)
     40
     41
     42def generate_challenge(verifier: str) -> str:
     43    hashed = hashlib.sha256(verifier.encode("utf-8")).digest()
     44    return base64.urlsafe_b64encode(hashed).decode("utf-8").replace("=", "")
     45
     46
     47def get_authentication_url(auth_server_port: int):
     48    code_challenge = generate_challenge(verifier)
     49    auth_url = "".join(
     50        [
     51            f"{settings.auth0_base_url}/authorize",
     52            "?response_type=code",
     53            f"&scope={settings.auth0_scope}",
     54            f"&audience={settings.auth0_audience}",
     55            f"&code_challenge={code_challenge}",
     56            "&code_challenge_method=S256",
     57            f"&client_id={settings.auth0_client_id}",
     58            f"&redirect_uri=http://localhost:{auth_server_port}",
     59        ]
     60    )
     61    return auth_url
     62
     63
     64queue = Queue()
     65
     66
     67@app.get("/")
     68async def main(request: Request, code):
     69    resp = await get_token(verifier, code, request.url.port)
     70    token = resp["access_token"]
     71    queue.put({"token": token})
     72    if token:
     73        return "Successfully authenticated, you may close this tab now"
     74    else:
     75        return "Failed to authenticate, please close this tab and try again"
     76
     77
     78@app.get("/login")
     79def login(request: Request):
     80    return RedirectResponse(
     81        url=get_authentication_url(auth_server_port=request.url.port)
     82    )
     83
     84
     85async def get_token(verifier: str, code: str, auth_server_port: int):
     86    url = f"{settings.auth0_base_url}/oauth/token"
     87    headers = {"content-type": "application/x-www-form-urlencoded"}
     88    data = {
     89        "grant_type": "authorization_code",
     90        "client_id": settings.auth0_client_id,
     91        "code_verifier": verifier,
     92        "code": code,
     93        "redirect_uri": f"http://localhost:{auth_server_port}",
     94    }
     95    resp = requests.post(
     96        url, headers=headers, data=data, allow_redirects=False, timeout=(5, 30)
     97    )
     98    return resp.json()
     99
    100
    101def get_user_token(auth_server_port: int = 8080) -> str:
    102    """A utility function required for getting Oqtant authenticated with your Oqtant account.
    103       Starts up a server to handle the Auth0 authentication process and acquire a token.
    104    Args:
    105        auth_server_port (int): optional port to run the authentication server on
    106    Returns:
    107        str: Auth0 user token
    108    """
    109    allowed_ports = [8080, 8081, 8082, 8083, 8084, 8085]
    110    if auth_server_port not in allowed_ports:
    111        raise ValueError(f"{auth_server_port} not in allowed ports: {allowed_ports}")
    112    server_config = uvicorn.Config(
    113        app=app, host="localhost", port=auth_server_port, log_level="error"
    114    )
    115    server = ThreadServer(config=server_config)
    116    with server.run_in_thread():
    117        webbrowser.open(f"http://localhost:{auth_server_port}/login")
    118        token = queue.get(block=True)
    119    return token["token"]

settings = Settings(auth0_base_url='https://coldquanta-dev.us.auth0.com', auth0_client_id='ZzQdn5ZZq1dmpP5N55KINr33u47RBRiu', auth0_scope='offline_access bec_dev_service:client', auth0_audience='https://oqtant.infleqtion.com/oqtant', signin_local_callback_url='http://localhost:8080', base_url='https://oqtant.infleqtion.com/api/jobs', max_ind_var=2, max_job_batch_size=30)
app = <fastapi.applications.FastAPI object>
router = <fastapi.routing.APIRouter object>
def generate_random(length: int) -> str: View Source

    36def generate_random(length: int) -> str:
    37    return base64.urlsafe_b64encode(os.urandom(length)).decode("utf-8").replace("=", "")

verifier = 'WZtKSU9nBiFJQQEIk0YyiNJ7gyisLy8GGZGbadM0YWzaHgV0BeM8Jc5JuKkFOmdP5EHXLWMHV0xWPnPRZp-ezfRL_gfvH3aBWzbeAqiIa0c'
def generate_challenge(verifier: str) -> str: View Source

    43def generate_challenge(verifier: str) -> str:
    44    hashed = hashlib.sha256(verifier.encode("utf-8")).digest()
    45    return base64.urlsafe_b64encode(hashed).decode("utf-8").replace("=", "")

def get_authentication_url(auth_server_port: int): View Source

    48def get_authentication_url(auth_server_port: int):
    49    code_challenge = generate_challenge(verifier)
    50    auth_url = "".join(
    51        [
    52            f"{settings.auth0_base_url}/authorize",
    53            "?response_type=code",
    54            f"&scope={settings.auth0_scope}",
    55            f"&audience={settings.auth0_audience}",
    56            f"&code_challenge={code_challenge}",
    57            "&code_challenge_method=S256",
    58            f"&client_id={settings.auth0_client_id}",
    59            f"&redirect_uri=http://localhost:{auth_server_port}",
    60        ]
    61    )
    62    return auth_url

queue = <multiprocessing.queues.Queue object>
@app.get('/')
async def main(request: starlette.requests.Request, code): View Source

    68@app.get("/")
    69async def main(request: Request, code):
    70    resp = await get_token(verifier, code, request.url.port)
    71    token = resp["access_token"]
    72    queue.put({"token": token})
    73    if token:
    74        return "Successfully authenticated, you may close this tab now"
    75    else:
    76        return "Failed to authenticate, please close this tab and try again"

@app.get('/login')
def login(request: starlette.requests.Request): View Source

    79@app.get("/login")
    80def login(request: Request):
    81    return RedirectResponse(
    82        url=get_authentication_url(auth_server_port=request.url.port)
    83    )

async def get_token(verifier: str, code: str, auth_server_port: int): View Source

    86async def get_token(verifier: str, code: str, auth_server_port: int):
    87    url = f"{settings.auth0_base_url}/oauth/token"
    88    headers = {"content-type": "application/x-www-form-urlencoded"}
    89    data = {
    90        "grant_type": "authorization_code",
    91        "client_id": settings.auth0_client_id,
    92        "code_verifier": verifier,
    93        "code": code,
    94        "redirect_uri": f"http://localhost:{auth_server_port}",
    95    }
    96    resp = requests.post(
    97        url, headers=headers, data=data, allow_redirects=False, timeout=(5, 30)
    98    )
    99    return resp.json()

def get_user_token(auth_server_port: int = 8080) -> str: View Source

    102def get_user_token(auth_server_port: int = 8080) -> str:
    103    """A utility function required for getting Oqtant authenticated with your Oqtant account.
    104       Starts up a server to handle the Auth0 authentication process and acquire a token.
    105    Args:
    106        auth_server_port (int): optional port to run the authentication server on
    107    Returns:
    108        str: Auth0 user token
    109    """
    110    allowed_ports = [8080, 8081, 8082, 8083, 8084, 8085]
    111    if auth_server_port not in allowed_ports:
    112        raise ValueError(f"{auth_server_port} not in allowed ports: {allowed_ports}")
    113    server_config = uvicorn.Config(
    114        app=app, host="localhost", port=auth_server_port, log_level="error"
    115    )
    116    server = ThreadServer(config=server_config)
    117    with server.run_in_thread():
    118        webbrowser.open(f"http://localhost:{auth_server_port}/login")
    119        token = queue.get(block=True)
    120    return token["token"]

A utility function required for getting Oqtant authenticated with your Oqtant account. Starts up a server to handle the Auth0 authentication process and acquire a token. Args: auth_server_port (int): optional port to run the authentication server on Returns: str: Auth0 user token