HHS / simpler-grants-gov

https://simpler.grants.gov
Other
43 stars 13 forks source link

Setup local oauth2 server for API to connect to #2668

Open chouinar opened 1 week ago

chouinar commented 1 week ago

Summary

We want to setup a local oauth2 server to connect to for the purposes of local development. Non-locally we'll be connecting to login.gov, but for local development we want something running on your host.

One possible implementation is https://github.com/navikt/mock-oauth2-server which looks like we can add to our docker-compose file.

Acceptance criteria

babebe commented 2 days ago

Update Docker-compose file with :

 mock-oauth2-server:
    image: pavitt/mock-oauth2-server:0.3.5
    ports:
      - "5000:5000"
    volumes:
      - ./config.json:/app/config.json
    environment:
      LOG_LEVEL: "debug"
      SERVER_PORT: 5000
      JSON_CONFIG_PATH: /app/config.json
      ISSUER_ID: http:localhost:5000`
    volumes:
      - ./config.json:/app/config.json
    networks:
      - grants_backend
      - default

Useful Debugger for requests and expected response : http://localhost:5000/default/debugger

Relevant Endpoints to call:

  1. authorization_endpoint: Use returned auth code to call token endpoint
  2. token_endpoint : Use returned token to call API endpoint
  3. jwks_uri : Get public keys to verify the signatures of JWTs issued by the server

API working sample implementation

@opportunity_blueprint.get("/authorize/logingov")
def login() ->  response.ApiResponse:
    import requests
    data = {
        "client_id": "client_id",
        "scope": "openid somescope",
        "response_type": "code",
        "redirect_uri": "http://grants-api:8080/v1/authorize/callback"
        "state": "checkforthisvalue"
    }

    resp = requests.get("http://mock-oauth2-server:5000/authorize", params=data)

    return  resp.text

@opportunity_blueprint.get("/authorize/callback")
def callback() -> response.ApiResponse:
    import requests

    #validate state value here
    request.args.get('state') == "checkforthisvalue"
    data = {
        "client_id": "client_id",
        "scope": "openid somescope",
        "grant_type": "authorization_code",
        "redirect_uri": "http://grants-api:8080/v1/authorize/callback",
        "code": request.args.get('code')
    }
    resp = requests.post("http://mock-oauth2-server:5000/token", data=data)
    token = resp.json()["id_token"]

    import jwt
    kid = jwt.get_unverified_header(token)["kid"]
    jwks = requests.get(f'http://mock-oauth2-server:5000/{kid}/jwks')

    return resp.text

#validate token