From c739b6c021980271bc6d23fe45a6185d9ad74b6e Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Thu, 4 May 2017 14:18:57 -0700 Subject: [PATCH 01/12] Create openapi-appengine.yaml --- .../getting-started/openapi-appengine.yaml | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 endpoints/getting-started/openapi-appengine.yaml diff --git a/endpoints/getting-started/openapi-appengine.yaml b/endpoints/getting-started/openapi-appengine.yaml new file mode 100644 index 00000000000..3e55ef27efc --- /dev/null +++ b/endpoints/getting-started/openapi-appengine.yaml @@ -0,0 +1,157 @@ +# [START swagger] +swagger: "2.0" +info: + description: "A simple Google Cloud Endpoints API example." + title: "Endpoints Example" + version: "1.0.0" +host: "[YOUR-PROJECT-ID].appspot.com" +# [END swagger] +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +schemes: +- "https" +paths: + "/echo": + post: + description: "Echo back a given message." + operationId: "echo" + produces: + - "application/json" + responses: + 200: + description: "Echo" + schema: + $ref: "#/definitions/echoMessage" + parameters: + - description: "Message to echo" + in: body + name: message + required: true + schema: + $ref: "#/definitions/echoMessage" + security: + - api_key: [] + "/auth/info/googlejwt": + get: + description: "Returns the requests' authentication information." + operationId: "auth_info_google_jwt" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - google_jwt: [] + - gae_default_service_account: [] + - google_service_account: [] + "/auth/info/googleidtoken": + get: + description: "Returns the requests' authentication information." + operationId: "authInfoGoogleIdToken" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - google_id_token: [] + "/auth/info/firebase": + get: + description: "Returns the requests' authentication information." + operationId: "authInfoFirebase" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - firebase: [] + +definitions: + echoMessage: + properties: + message: + type: "string" + authInfoResponse: + properties: + id: + type: "string" + email: + type: "string" +# [START securityDef] +securityDefinitions: + # This section configures basic authentication with an API key. + api_key: + type: "apiKey" + name: "key" + in: "query" +# [END securityDef] + # This section configures authentication using Google API Service Accounts + # to sign a json web token. This is mostly used for server-to-server + # communication. + google_jwt: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # This must match the 'iss' field in the JWT. + x-google-issuer: "jwt-client.endpoints.sample.google.com" + # Update this with your service account's email address. + x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using Google App Engine default + # service account to sign a json web token. This is mostly used for + # server-to-server communication. + gae_default_service_account: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. + x-google-issuer: "YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" + # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. + x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using a service account + # to sign a json web token. This is mostly used for server-to-server + # communication. + google_service_account: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. + x-google-issuer: "YOUR-SERVICE-ACCOUNT-EMAIL" + # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. + x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-SERVICE-ACCOUNT-EMAIL" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using Google OAuth2 ID Tokens. + # ID Tokens can be obtained using OAuth2 clients, and can be used to access + # your API on behalf of a particular user. + google_id_token: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + x-google-issuer: "https://accounts.google.com" + x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs" + # Your OAuth2 client's Client ID must be added here. You can add multiple client IDs to accept tokens form multiple clients. + x-google-audiences: "YOUR-CLIENT-ID" + # This section configures authentication using Firebase Auth. + # [START firebaseAuth] + firebase: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID" + x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com" + x-google-audiences: "YOUR-PROJECT-ID" + # [END firebaseAuth] From 012ba83a503cf29e967d03f9630c0cd51e276235 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Tue, 9 May 2017 14:08:58 -0700 Subject: [PATCH 02/12] Add comment to openapi.yaml about deploying on App Engine. Remove openapi-appengine.yaml. --- .../getting-started/openapi-appengine.yaml | 157 ------------------ endpoints/getting-started/openapi.yaml | 3 + 2 files changed, 3 insertions(+), 157 deletions(-) delete mode 100644 endpoints/getting-started/openapi-appengine.yaml diff --git a/endpoints/getting-started/openapi-appengine.yaml b/endpoints/getting-started/openapi-appengine.yaml deleted file mode 100644 index 3e55ef27efc..00000000000 --- a/endpoints/getting-started/openapi-appengine.yaml +++ /dev/null @@ -1,157 +0,0 @@ -# [START swagger] -swagger: "2.0" -info: - description: "A simple Google Cloud Endpoints API example." - title: "Endpoints Example" - version: "1.0.0" -host: "[YOUR-PROJECT-ID].appspot.com" -# [END swagger] -basePath: "/" -consumes: -- "application/json" -produces: -- "application/json" -schemes: -- "https" -paths: - "/echo": - post: - description: "Echo back a given message." - operationId: "echo" - produces: - - "application/json" - responses: - 200: - description: "Echo" - schema: - $ref: "#/definitions/echoMessage" - parameters: - - description: "Message to echo" - in: body - name: message - required: true - schema: - $ref: "#/definitions/echoMessage" - security: - - api_key: [] - "/auth/info/googlejwt": - get: - description: "Returns the requests' authentication information." - operationId: "auth_info_google_jwt" - produces: - - "application/json" - responses: - 200: - description: "Authentication info." - schema: - $ref: "#/definitions/authInfoResponse" - security: - - google_jwt: [] - - gae_default_service_account: [] - - google_service_account: [] - "/auth/info/googleidtoken": - get: - description: "Returns the requests' authentication information." - operationId: "authInfoGoogleIdToken" - produces: - - "application/json" - responses: - 200: - description: "Authentication info." - schema: - $ref: "#/definitions/authInfoResponse" - security: - - google_id_token: [] - "/auth/info/firebase": - get: - description: "Returns the requests' authentication information." - operationId: "authInfoFirebase" - produces: - - "application/json" - responses: - 200: - description: "Authentication info." - schema: - $ref: "#/definitions/authInfoResponse" - security: - - firebase: [] - -definitions: - echoMessage: - properties: - message: - type: "string" - authInfoResponse: - properties: - id: - type: "string" - email: - type: "string" -# [START securityDef] -securityDefinitions: - # This section configures basic authentication with an API key. - api_key: - type: "apiKey" - name: "key" - in: "query" -# [END securityDef] - # This section configures authentication using Google API Service Accounts - # to sign a json web token. This is mostly used for server-to-server - # communication. - google_jwt: - authorizationUrl: "" - flow: "implicit" - type: "oauth2" - # This must match the 'iss' field in the JWT. - x-google-issuer: "jwt-client.endpoints.sample.google.com" - # Update this with your service account's email address. - x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL" - # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. - x-google-audiences: "echo.endpoints.sample.google.com" - # This section configures authentication using Google App Engine default - # service account to sign a json web token. This is mostly used for - # server-to-server communication. - gae_default_service_account: - authorizationUrl: "" - flow: "implicit" - type: "oauth2" - # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. - x-google-issuer: "YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" - # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. - x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" - # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. - x-google-audiences: "echo.endpoints.sample.google.com" - # This section configures authentication using a service account - # to sign a json web token. This is mostly used for server-to-server - # communication. - google_service_account: - authorizationUrl: "" - flow: "implicit" - type: "oauth2" - # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. - x-google-issuer: "YOUR-SERVICE-ACCOUNT-EMAIL" - # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. - x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-SERVICE-ACCOUNT-EMAIL" - # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. - x-google-audiences: "echo.endpoints.sample.google.com" - # This section configures authentication using Google OAuth2 ID Tokens. - # ID Tokens can be obtained using OAuth2 clients, and can be used to access - # your API on behalf of a particular user. - google_id_token: - authorizationUrl: "" - flow: "implicit" - type: "oauth2" - x-google-issuer: "https://accounts.google.com" - x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs" - # Your OAuth2 client's Client ID must be added here. You can add multiple client IDs to accept tokens form multiple clients. - x-google-audiences: "YOUR-CLIENT-ID" - # This section configures authentication using Firebase Auth. - # [START firebaseAuth] - firebase: - authorizationUrl: "" - flow: "implicit" - type: "oauth2" - x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID" - x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com" - x-google-audiences: "YOUR-PROJECT-ID" - # [END firebaseAuth] diff --git a/endpoints/getting-started/openapi.yaml b/endpoints/getting-started/openapi.yaml index 160ceafc1fd..ead6b3c3a69 100644 --- a/endpoints/getting-started/openapi.yaml +++ b/endpoints/getting-started/openapi.yaml @@ -6,6 +6,9 @@ info: version: "1.0.0" host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog" # [END swagger] +# For App Engine deployments, delete the above "host:" line and remove the "# " +# from the following line. Then change YOUR-PROJECT-ID to your project id. +# host: "YOUR-PROJECT-ID.appspot.com" basePath: "/" consumes: - "application/json" From f900dadbbeacc8bff0676aa45f723cd56a67f245 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Thu, 15 Jun 2017 14:02:02 -0700 Subject: [PATCH 03/12] Add query string authentication option to Endpoints clients. --- .../clients/google-jwt-client.py | 19 ++++++++++++------- .../service_to_service_gae_default/main.py | 12 +++++++++--- .../main.py | 18 ++++++++++++------ .../service_to_service_non_default/main.py | 12 +++++++++--- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/endpoints/getting-started/clients/google-jwt-client.py b/endpoints/getting-started/clients/google-jwt-client.py index 076b656f6be..c85bb7d81b4 100644 --- a/endpoints/getting-started/clients/google-jwt-client.py +++ b/endpoints/getting-started/clients/google-jwt-client.py @@ -53,15 +53,19 @@ def generate_jwt(service_account_file): return signed_jwt -def make_request(host, api_key, signed_jwt): +def make_request(host, api_key, signed_jwt, use_query_string_auth=False): """Makes a request to the auth info endpoint for Google JWTs.""" url = urllib.parse.urljoin(host, '/auth/info/googlejwt') - params = { - 'key': api_key - } - headers = { - 'Authorization': 'Bearer {}'.format(signed_jwt) - } + if use_query_string_auth: + params = { + 'key': api_key, + 'access_token': signed_jwt} + headers = None + else: + params = { + 'key': api_key} + headers = { + 'Authorization': 'Bearer {}'.format(signed_jwt)} response = requests.get(url, params=params, headers=headers) @@ -71,6 +75,7 @@ def make_request(host, api_key, signed_jwt): def main(host, api_key, service_account_file): signed_jwt = generate_jwt(service_account_file) + # To use query string authentication, add use_query_string_auth=True. response = make_request(host, api_key, signed_jwt) print(response) diff --git a/endpoints/getting-started/clients/service_to_service_gae_default/main.py b/endpoints/getting-started/clients/service_to_service_gae_default/main.py index cfa49c35835..a7c7d7ef26d 100644 --- a/endpoints/getting-started/clients/service_to_service_gae_default/main.py +++ b/endpoints/getting-started/clients/service_to_service_gae_default/main.py @@ -60,11 +60,16 @@ def generate_jwt(): return signed_jwt -def make_request(signed_jwt): +def make_request(signed_jwt, use_query_string_auth=False): """Makes a request to the auth info endpoint for Google JWTs.""" - headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} + if use_query_string_auth: + headers = None + url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) + else: + headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} + url = '/auth/info/googleidsigned_jwt' conn = httplib.HTTPSConnection(HOST) - conn.request("GET", '/auth/info/googlejwt', None, headers) + conn.request("GET", url, None, headers) res = conn.getresponse() conn.close() return res.read() @@ -74,6 +79,7 @@ class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' signed_jwt = generate_jwt() + # To use query string authentication, add use_query_string_auth=True. res = make_request(signed_jwt) self.response.write(res) diff --git a/endpoints/getting-started/clients/service_to_service_google_id_token/main.py b/endpoints/getting-started/clients/service_to_service_google_id_token/main.py index e943200f929..3db5f0a7535 100644 --- a/endpoints/getting-started/clients/service_to_service_google_id_token/main.py +++ b/endpoints/getting-started/clients/service_to_service_google_id_token/main.py @@ -74,11 +74,16 @@ def get_id_token(): return res['id_token'] -def make_request(token): - """Makes a request to the auth info endpoint for Google ID token.""" - headers = {'Authorization': 'Bearer {}'.format(token)} +def make_request(signed_jwt, use_query_string_auth=False): + """Makes a request to the auth info endpoint for Google ID signed_jwt.""" + if use_query_string_auth: + headers = None + url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) + else: + headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} + url = '/auth/info/googleidsigned_jwt' conn = httplib.HTTPSConnection(HOST) - conn.request("GET", '/auth/info/googleidtoken', None, headers) + conn.request("GET", url, None, headers) res = conn.getresponse() conn.close() return res.read() @@ -87,8 +92,9 @@ def make_request(token): class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' - token = get_id_token() - res = make_request(token) + signed_jwt = get_id_signed_jwt() + # To use query string authentication, add use_query_string_auth=True. + res = make_request(signed_jwt) self.response.write(res) diff --git a/endpoints/getting-started/clients/service_to_service_non_default/main.py b/endpoints/getting-started/clients/service_to_service_non_default/main.py index 3ad87473062..7c43e3159dd 100644 --- a/endpoints/getting-started/clients/service_to_service_non_default/main.py +++ b/endpoints/getting-started/clients/service_to_service_non_default/main.py @@ -72,11 +72,16 @@ def generate_jwt(): return signed_jwt -def make_request(signed_jwt): +def make_request(signed_jwt, use_query_string_auth=False): """Makes a request to the auth info endpoint for Google JWTs.""" - headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} + if use_query_string_auth: + headers = None + url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) + else: + headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} + url = '/auth/info/googleidsigned_jwt' conn = httplib.HTTPSConnection(HOST) - conn.request("GET", '/auth/info/googlejwt', None, headers) + conn.request("GET", url, None, headers) res = conn.getresponse() conn.close() return res.read() @@ -86,6 +91,7 @@ class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' signed_jwt = generate_jwt() + # To use query string authentication, add use_query_string_auth=True. res = make_request(signed_jwt) self.response.write(res) From 3756a2d82c30699905cf82cc852592dc8a742d16 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Thu, 15 Jun 2017 14:08:57 -0700 Subject: [PATCH 04/12] Fix bracket line spacing. --- endpoints/getting-started/clients/google-jwt-client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/endpoints/getting-started/clients/google-jwt-client.py b/endpoints/getting-started/clients/google-jwt-client.py index c85bb7d81b4..2a9f47b5769 100644 --- a/endpoints/getting-started/clients/google-jwt-client.py +++ b/endpoints/getting-started/clients/google-jwt-client.py @@ -59,13 +59,16 @@ def make_request(host, api_key, signed_jwt, use_query_string_auth=False): if use_query_string_auth: params = { 'key': api_key, - 'access_token': signed_jwt} + 'access_token': signed_jwt + } headers = None else: params = { - 'key': api_key} + 'key': api_key + } headers = { - 'Authorization': 'Bearer {}'.format(signed_jwt)} + 'Authorization': 'Bearer {}'.format(signed_jwt) + } response = requests.get(url, params=params, headers=headers) From 5ae5482473d7adc12b4f62b4a810ce8a648ac1b6 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Mon, 24 Jul 2017 12:32:48 -0700 Subject: [PATCH 05/12] Add openapi-appengine.yaml file for App Engine deployments. --- .../getting-started/openapi-appengine.yaml | 157 ++++++++++++++++++ endpoints/getting-started/openapi.yaml | 3 - 2 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 endpoints/getting-started/openapi-appengine.yaml diff --git a/endpoints/getting-started/openapi-appengine.yaml b/endpoints/getting-started/openapi-appengine.yaml new file mode 100644 index 00000000000..785bf04955a --- /dev/null +++ b/endpoints/getting-started/openapi-appengine.yaml @@ -0,0 +1,157 @@ +# [START swagger] +swagger: "2.0" +info: + description: "A simple Google Cloud Endpoints API example." + title: "Endpoints Example" + version: "1.0.0" +host: "YOUR-PROJECT-ID.appspot.com" +# [END swagger] +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +schemes: +- "https" +paths: + "/echo": + post: + description: "Echo back a given message." + operationId: "echo" + produces: + - "application/json" + responses: + 200: + description: "Echo" + schema: + $ref: "#/definitions/echoMessage" + parameters: + - description: "Message to echo" + in: body + name: message + required: true + schema: + $ref: "#/definitions/echoMessage" + security: + - api_key: [] + "/auth/info/googlejwt": + get: + description: "Returns the requests' authentication information." + operationId: "auth_info_google_jwt" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - google_jwt: [] + - gae_default_service_account: [] + - google_service_account: [] + "/auth/info/googleidtoken": + get: + description: "Returns the requests' authentication information." + operationId: "authInfoGoogleIdToken" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - google_id_token: [] + "/auth/info/firebase": + get: + description: "Returns the requests' authentication information." + operationId: "authInfoFirebase" + produces: + - "application/json" + responses: + 200: + description: "Authentication info." + schema: + $ref: "#/definitions/authInfoResponse" + security: + - firebase: [] + +definitions: + echoMessage: + properties: + message: + type: "string" + authInfoResponse: + properties: + id: + type: "string" + email: + type: "string" +# [START securityDef] +securityDefinitions: + # This section configures basic authentication with an API key. + api_key: + type: "apiKey" + name: "key" + in: "query" +# [END securityDef] + # This section configures authentication using Google API Service Accounts + # to sign a json web token. This is mostly used for server-to-server + # communication. + google_jwt: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # This must match the 'iss' field in the JWT. + x-google-issuer: "jwt-client.endpoints.sample.google.com" + # Update this with your service account's email address. + x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using Google App Engine default + # service account to sign a json web token. This is mostly used for + # server-to-server communication. + gae_default_service_account: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. + x-google-issuer: "YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" + # Replace YOUR-CLIENT-PROJECT-ID with your client project ID. + x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-CLIENT-PROJECT-ID@appspot.gserviceaccount.com" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using a service account + # to sign a json web token. This is mostly used for server-to-server + # communication. + google_service_account: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. + x-google-issuer: "YOUR-SERVICE-ACCOUNT-EMAIL" + # Replace YOUR-SERVICE-ACCOUNT-EMAIL with your service account email. + x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/YOUR-SERVICE-ACCOUNT-EMAIL" + # This must match the "aud" field in the JWT. You can add multiple audiences to accept JWTs from multiple clients. + x-google-audiences: "echo.endpoints.sample.google.com" + # This section configures authentication using Google OAuth2 ID Tokens. + # ID Tokens can be obtained using OAuth2 clients, and can be used to access + # your API on behalf of a particular user. + google_id_token: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + x-google-issuer: "https://accounts.google.com" + x-google-jwks_uri: "https://www.googleapis.com/oauth2/v3/certs" + # Your OAuth2 client's Client ID must be added here. You can add multiple client IDs to accept tokens form multiple clients. + x-google-audiences: "YOUR-CLIENT-ID" + # This section configures authentication using Firebase Auth. + # [START firebaseAuth] + firebase: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID" + x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com" + x-google-audiences: "YOUR-PROJECT-ID" + # [END firebaseAuth] diff --git a/endpoints/getting-started/openapi.yaml b/endpoints/getting-started/openapi.yaml index ead6b3c3a69..160ceafc1fd 100644 --- a/endpoints/getting-started/openapi.yaml +++ b/endpoints/getting-started/openapi.yaml @@ -6,9 +6,6 @@ info: version: "1.0.0" host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog" # [END swagger] -# For App Engine deployments, delete the above "host:" line and remove the "# " -# from the following line. Then change YOUR-PROJECT-ID to your project id. -# host: "YOUR-PROJECT-ID.appspot.com" basePath: "/" consumes: - "application/json" From 3cc284d34c13095cc708bfd83b5c3cb18785686c Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Mon, 24 Jul 2017 13:11:28 -0700 Subject: [PATCH 06/12] Remove alternative auth scheme. --- .../clients/google-jwt-client.py | 22 ++++++------------- .../service_to_service_gae_default/main.py | 12 +++------- .../main.py | 18 +++++---------- .../service_to_service_non_default/main.py | 12 +++------- 4 files changed, 19 insertions(+), 45 deletions(-) diff --git a/endpoints/getting-started/clients/google-jwt-client.py b/endpoints/getting-started/clients/google-jwt-client.py index 9b903a4cc34..ad1c3d74f89 100644 --- a/endpoints/getting-started/clients/google-jwt-client.py +++ b/endpoints/getting-started/clients/google-jwt-client.py @@ -60,22 +60,15 @@ def generate_jwt(service_account_file): return jwt -def make_request(host, api_key, signed_jwt, use_query_string_auth=False): +def make_request(host, api_key, signed_jwt): """Makes a request to the auth info endpoint for Google JWTs.""" url = urllib.parse.urljoin(host, '/auth/info/googlejwt') - if use_query_string_auth: - params = { - 'key': api_key, - 'access_token': signed_jwt - } - headers = None - else: - params = { - 'key': api_key - } - headers = { - 'Authorization': 'Bearer {}'.format(signed_jwt) - } + params = { + 'key': api_key + } + headers = { + 'Authorization': 'Bearer {}'.format(signed_jwt) + } response = requests.get(url, params=params, headers=headers) @@ -85,7 +78,6 @@ def make_request(host, api_key, signed_jwt, use_query_string_auth=False): def main(host, api_key, service_account_file): signed_jwt = generate_jwt(service_account_file) - # To use query string authentication, add use_query_string_auth=True. response = make_request(host, api_key, signed_jwt) print(response) diff --git a/endpoints/getting-started/clients/service_to_service_gae_default/main.py b/endpoints/getting-started/clients/service_to_service_gae_default/main.py index 46d86406dcd..4609eee8a6d 100644 --- a/endpoints/getting-started/clients/service_to_service_gae_default/main.py +++ b/endpoints/getting-started/clients/service_to_service_gae_default/main.py @@ -60,16 +60,11 @@ def generate_jwt(): return signed_jwt -def make_request(signed_jwt, use_query_string_auth=False): +def make_request(signed_jwt): """Makes a request to the auth info endpoint for Google JWTs.""" - if use_query_string_auth: - headers = None - url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) - else: - headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} - url = '/auth/info/googleidsigned_jwt' + headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} conn = httplib.HTTPSConnection(HOST) - conn.request("GET", url, None, headers) + conn.request("GET", '/auth/info/googlejwt', None, headers) res = conn.getresponse() conn.close() return res.read() @@ -79,7 +74,6 @@ class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' signed_jwt = generate_jwt() - # To use query string authentication, add use_query_string_auth=True. res = make_request(signed_jwt) self.response.write(res) diff --git a/endpoints/getting-started/clients/service_to_service_google_id_token/main.py b/endpoints/getting-started/clients/service_to_service_google_id_token/main.py index c080fec7de2..b0033ff1589 100644 --- a/endpoints/getting-started/clients/service_to_service_google_id_token/main.py +++ b/endpoints/getting-started/clients/service_to_service_google_id_token/main.py @@ -74,16 +74,11 @@ def get_id_token(): return res['id_token'] -def make_request(signed_jwt, use_query_string_auth=False): - """Makes a request to the auth info endpoint for Google ID signed_jwt.""" - if use_query_string_auth: - headers = None - url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) - else: - headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} - url = '/auth/info/googleidsigned_jwt' +def make_request(token): + """Makes a request to the auth info endpoint for Google ID token.""" + headers = {'Authorization': 'Bearer {}'.format(token)} conn = httplib.HTTPSConnection(HOST) - conn.request("GET", url, None, headers) + conn.request("GET", '/auth/info/googleidtoken', None, headers) res = conn.getresponse() conn.close() return res.read() @@ -92,9 +87,8 @@ def make_request(signed_jwt, use_query_string_auth=False): class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' - signed_jwt = get_id_signed_jwt() - # To use query string authentication, add use_query_string_auth=True. - res = make_request(signed_jwt) + token = get_id_token() + res = make_request(token) self.response.write(res) diff --git a/endpoints/getting-started/clients/service_to_service_non_default/main.py b/endpoints/getting-started/clients/service_to_service_non_default/main.py index 299ab3f3795..361a99e1e6a 100644 --- a/endpoints/getting-started/clients/service_to_service_non_default/main.py +++ b/endpoints/getting-started/clients/service_to_service_non_default/main.py @@ -70,16 +70,11 @@ def generate_jwt(): return signed_jwt -def make_request(signed_jwt, use_query_string_auth=False): +def make_request(signed_jwt): """Makes a request to the auth info endpoint for Google JWTs.""" - if use_query_string_auth: - headers = None - url = '/auth/info/googleidsigned_jwt?access_token={}'.format(signed_jwt) - else: - headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} - url = '/auth/info/googleidsigned_jwt' + headers = {'Authorization': 'Bearer {}'.format(signed_jwt)} conn = httplib.HTTPSConnection(HOST) - conn.request("GET", url, None, headers) + conn.request("GET", '/auth/info/googlejwt', None, headers) res = conn.getresponse() conn.close() return res.read() @@ -89,7 +84,6 @@ class MainPage(webapp2.RequestHandler): def get(self): self.response.headers['Content-Type'] = 'text/plain' signed_jwt = generate_jwt() - # To use query string authentication, add use_query_string_auth=True. res = make_request(signed_jwt) self.response.write(res) From 6d6602b36c800de0d789fc3283b150157bfb058f Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Fri, 25 Aug 2017 14:51:46 -0700 Subject: [PATCH 07/12] Change cloud.goog to appspot.com --- appengine/standard/endpoints-frameworks-v2/echo/app.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appengine/standard/endpoints-frameworks-v2/echo/app.yaml b/appengine/standard/endpoints-frameworks-v2/echo/app.yaml index e8585189941..af0a8d014e3 100644 --- a/appengine/standard/endpoints-frameworks-v2/echo/app.yaml +++ b/appengine/standard/endpoints-frameworks-v2/echo/app.yaml @@ -28,5 +28,5 @@ libraries: env_variables: # The following values are to be replaced by information from the output of # 'gcloud service-management deploy swagger.json' command. - ENDPOINTS_SERVICE_NAME: echo-api.endpoints.[YOUR-PROJECT-ID].cloud.goog + ENDPOINTS_SERVICE_NAME: YOUR-PROJECT-ID.appspot.com ENDPOINTS_SERVICE_VERSION: 2016-08-01r0 From 4619ff5cff1c1671f9fb28756b975ec57f0ed8d4 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Wed, 6 Sep 2017 21:19:38 +0000 Subject: [PATCH 08/12] Add simple IAP app for GCE. --- iap/example_gce_backend.py | 28 ++++++++++++++++++++++++++++ iap/requirements.txt | 1 + 2 files changed, 29 insertions(+) create mode 100755 iap/example_gce_backend.py diff --git a/iap/example_gce_backend.py b/iap/example_gce_backend.py new file mode 100755 index 00000000000..64cf1ff71dc --- /dev/null +++ b/iap/example_gce_backend.py @@ -0,0 +1,28 @@ +CLOUD_PROJECT_ID = 'YOUR_PROJECT_ID' +BACKEND_SERVICE_ID = 'YOUR_BACKEND_SERVICE_ID' + +from flask import Flask +from flask import request + +import validate_jwt + +app = Flask(__name__) + +@app.route('/') +def root(): + jwt = request.headers.get('x-goog-iap-jwt-assertion') + if jwt is None: + return 'Unauthorized request.', 401 + user_id, user_email, error_str = validate_jwt.validate_iap_jwt_from_compute_engine( + jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) + if error_str: + return "Error: %s" % error_str + else: + return "Hi, %s" % user_email + +@app.route('/healthz') +def health(): + return 'OK', 200 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=80) diff --git a/iap/requirements.txt b/iap/requirements.txt index 10364102fb7..27402d2b348 100644 --- a/iap/requirements.txt +++ b/iap/requirements.txt @@ -1,5 +1,6 @@ PyJWT==1.5.2 cryptography==2.0.3 +flask google-auth==1.0.2 requests==2.18.4 requests_toolbelt==0.8.0 From a6a9ac3b479614d7f6c4c88f3dc40b8a78decd2c Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Thu, 7 Sep 2017 16:14:57 -0700 Subject: [PATCH 09/12] Add hostname to example app's response. --- iap/example_gce_backend.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iap/example_gce_backend.py b/iap/example_gce_backend.py index 64cf1ff71dc..ebf51384dd1 100755 --- a/iap/example_gce_backend.py +++ b/iap/example_gce_backend.py @@ -4,7 +4,9 @@ from flask import Flask from flask import request -import validate_jwt +import platform + +from validate_jwt import validate_iap_jwt_from_compute_engine app = Flask(__name__) @@ -13,12 +15,12 @@ def root(): jwt = request.headers.get('x-goog-iap-jwt-assertion') if jwt is None: return 'Unauthorized request.', 401 - user_id, user_email, error_str = validate_jwt.validate_iap_jwt_from_compute_engine( + user_id, user_email, error_str = validate_iap_jwt_from_compute_engine( jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) if error_str: return "Error: %s" % error_str else: - return "Hi, %s" % user_email + return "Hi, {}. I am {}.".format(user_email, platform.node()) @app.route('/healthz') def health(): From aa5fa11faacc06975391238d5003f3aac941e7a2 Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Tue, 12 Sep 2017 13:05:30 -0700 Subject: [PATCH 10/12] Update IAP example backend and requirements. --- iap/example_gce_backend.py | 38 +++++++++++++++++++++++++++----------- iap/requirements.txt | 3 ++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/iap/example_gce_backend.py b/iap/example_gce_backend.py index ebf51384dd1..c87df1ce5e5 100755 --- a/iap/example_gce_backend.py +++ b/iap/example_gce_backend.py @@ -1,30 +1,46 @@ +# Copyright 2017 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + CLOUD_PROJECT_ID = 'YOUR_PROJECT_ID' BACKEND_SERVICE_ID = 'YOUR_BACKEND_SERVICE_ID' -from flask import Flask -from flask import request - import platform -from validate_jwt import validate_iap_jwt_from_compute_engine +import flask + +import validate_jwt + +app = flask.Flask(__name__) -app = Flask(__name__) @app.route('/') def root(): - jwt = request.headers.get('x-goog-iap-jwt-assertion') + jwt = flask.request.headers.get('x-goog-iap-jwt-assertion') if jwt is None: return 'Unauthorized request.', 401 - user_id, user_email, error_str = validate_iap_jwt_from_compute_engine( - jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) + user_id, user_email, error_str = validate_jwt.validate_iap_jwt_from_compute_engine( + jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) if error_str: - return "Error: %s" % error_str + return 'Error: {}'.format(error_str) else: - return "Hi, {}. I am {}.".format(user_email, platform.node()) + return 'Hi, {}. I am {}.'.format(user_email, platform.node()) + @app.route('/healthz') def health(): return 'OK', 200 + if __name__ == '__main__': - app.run(host='0.0.0.0', port=80) + app.run() diff --git a/iap/requirements.txt b/iap/requirements.txt index 27402d2b348..b170308b884 100644 --- a/iap/requirements.txt +++ b/iap/requirements.txt @@ -1,6 +1,7 @@ PyJWT==1.5.2 cryptography==2.0.3 -flask +flask==0.12.2 google-auth==1.0.2 +gunicorn==19.7.1 requests==2.18.4 requests_toolbelt==0.8.0 From 197cfd1b27602875b570e7dea53ecdca6fd1264c Mon Sep 17 00:00:00 2001 From: Paul Buser Date: Wed, 13 Sep 2017 12:22:54 -0700 Subject: [PATCH 11/12] Remove unnecessary '/healthz' endpoint, move constants after imports. --- iap/example_gce_backend.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/iap/example_gce_backend.py b/iap/example_gce_backend.py index c87df1ce5e5..05e7d6ae4ca 100755 --- a/iap/example_gce_backend.py +++ b/iap/example_gce_backend.py @@ -12,15 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -CLOUD_PROJECT_ID = 'YOUR_PROJECT_ID' -BACKEND_SERVICE_ID = 'YOUR_BACKEND_SERVICE_ID' - import platform import flask import validate_jwt +CLOUD_PROJECT_ID = 'YOUR_PROJECT_ID' +BACKEND_SERVICE_ID = 'YOUR_BACKEND_SERVICE_ID' + app = flask.Flask(__name__) @@ -28,7 +28,7 @@ def root(): jwt = flask.request.headers.get('x-goog-iap-jwt-assertion') if jwt is None: - return 'Unauthorized request.', 401 + return 'Unauthorized request.' user_id, user_email, error_str = validate_jwt.validate_iap_jwt_from_compute_engine( jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) if error_str: @@ -37,10 +37,5 @@ def root(): return 'Hi, {}. I am {}.'.format(user_email, platform.node()) -@app.route('/healthz') -def health(): - return 'OK', 200 - - if __name__ == '__main__': app.run() From 843fc64f5f7d088524ed0ccd24bf1058c5d0060a Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Wed, 13 Sep 2017 12:27:54 -0700 Subject: [PATCH 12/12] Fix lint --- iap/example_gce_backend.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iap/example_gce_backend.py b/iap/example_gce_backend.py index 05e7d6ae4ca..292532bc2a1 100755 --- a/iap/example_gce_backend.py +++ b/iap/example_gce_backend.py @@ -29,8 +29,9 @@ def root(): jwt = flask.request.headers.get('x-goog-iap-jwt-assertion') if jwt is None: return 'Unauthorized request.' - user_id, user_email, error_str = validate_jwt.validate_iap_jwt_from_compute_engine( - jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID) + user_id, user_email, error_str = ( + validate_jwt.validate_iap_jwt_from_compute_engine( + jwt, CLOUD_PROJECT_ID, BACKEND_SERVICE_ID)) if error_str: return 'Error: {}'.format(error_str) else: