about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaude Sonnet 4.62026-06-15 17:37:00 +0000
committerFrederick Muriuki Muriithi2026-06-15 12:59:34 -0500
commit3ac89fabe4070b4c1343f93f4e2bca9d0e612cbc (patch)
tree228c8b39505955d2a7771b7785bf4f005452a538
parentb34a606fbffcf3c2baf1ceb234f6990928d82564 (diff)
downloadgn-integration-tests-3ac89fabe4070b4c1343f93f4e2bca9d0e612cbc.tar.gz
tests: add TestTokenGrant auth-flow tests
Test that POST /auth/token with valid admin credentials returns 200,
includes an access_token, sets token_type to bearer, and grants at
least the requested scopes.
-rw-r--r--tests/test_gn_auth_auth_flow.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/tests/test_gn_auth_auth_flow.py b/tests/test_gn_auth_auth_flow.py
new file mode 100644
index 0000000..ab26f10
--- /dev/null
+++ b/tests/test_gn_auth_auth_flow.py
@@ -0,0 +1,79 @@
+"""
+Auth-flow integration tests for gn-auth.
+
+Require live credentials set up by the CI test-session lifecycle
+(create-test-users / create-test-oauth2-client).  Run with:
+
+    pytest -m "gn_auth and auth_flow"
+
+Environment variables:
+
+    GN_TEST_EMAIL            admin test-user email
+    GN_TEST_PASSWORD         admin test-user password
+    GN_TEST_BASIC_EMAIL      unprivileged test-user email
+    GN_TEST_BASIC_PASSWORD   unprivileged test-user password
+    GN_OAUTH2_CLIENT_ID      OAuth2 client UUID
+    GN_OAUTH2_CLIENT_SECRET  OAuth2 client secret
+"""
+
+import pytest
+
+pytestmark = [pytest.mark.gn_auth, pytest.mark.auth_flow]
+
+
+# ---------------------------------------------------------------------------
+# POST /auth/token — password grant with valid credentials
+# ---------------------------------------------------------------------------
+
+class TestTokenGrant:
+    """Password grant with valid admin credentials issues a usable token."""
+
+    def _post_token(self, gn_auth_url, http, oauth2_credentials,
+                    scope="profile group resource"):
+        email, password, client_id, client_secret = oauth2_credentials
+        return http.post(
+            f"{gn_auth_url}/auth/token",
+            json={
+                "grant_type": "password",
+                "username": email,
+                "password": password,
+                "scope": scope,
+                "client_id": client_id,
+                "client_secret": client_secret,
+            },
+            timeout=30,
+        )
+
+    def test_valid_credentials_return_200(
+            self, gn_auth_url, http, oauth2_credentials):
+        resp = self._post_token(gn_auth_url, http, oauth2_credentials)
+        assert resp.status_code == 200, (
+            f"Expected 200 from token endpoint, got {resp.status_code}: {resp.text}"
+        )
+
+    def test_response_contains_access_token(
+            self, gn_auth_url, http, oauth2_credentials):
+        resp = self._post_token(gn_auth_url, http, oauth2_credentials)
+        data = resp.json()
+        assert "access_token" in data, (
+            f"Token response missing 'access_token': {data}"
+        )
+
+    def test_token_type_is_bearer(
+            self, gn_auth_url, http, oauth2_credentials):
+        resp = self._post_token(gn_auth_url, http, oauth2_credentials)
+        token_type = resp.json().get("token_type", "")
+        assert token_type.lower() == "bearer", (
+            f"Expected token_type 'bearer', got: {token_type!r}"
+        )
+
+    def test_granted_scope_covers_requested(
+            self, gn_auth_url, http, oauth2_credentials):
+        requested = {"profile", "group", "resource"}
+        resp = self._post_token(gn_auth_url, http, oauth2_credentials)
+        data = resp.json()
+        assert "scope" in data, f"Token response missing 'scope': {data}"
+        granted = set(data["scope"].split())
+        assert requested <= granted, (
+            f"Requested scopes {requested} not all in granted scopes {granted}"
+        )