Google Identity Platform OAuth server - google-cloud-platform

I want to user Google Identity Platform as the CIAM solution for our GKE-based cloud service. We have a requirement to allow 3rd parties to access our cloud APIs using credentials they obtain via OAuth.
For example, our cloud service provides APIs that Google Assistant or Amazon Alexa can access on behalf of our users. Therefore, we want to provide an OAuth-based token manager that uses the identities of our customers as defined in the Google Identity Platform.
Is this type of OAuth service possible using Google Identity Platform, or the underlying Firebase service that drives it?

Based on the documentation for Google Assistant, you will need to implement your own OAuth2 endpoints. In the authorization code flow, you need two endpoints:
The authentication endpoint needs to sign in the user and get their permission to allow the third party (eg. Google) to call the customer's API on their behalf. If the user gives permission then they return an authorization code - which could be implemented by creating a custom token with Cloud Identity Platform.
Token exchange endpoint is also needed, which has two functions. The first is to exchange the authorization code created by the first endpoint for a refresh token and an ID token. The second is to exchange a refresh token for a new ID token. Both of these functions can be delegated to Cloud Identity Platform.
Additional note:
I would suggest to use custom claims to ensure that these tokens can only be used for the intended purposes, ie. to perform actions which the Google Assistant needs to do. Users shouldn't be allowed to perform other actions, eg. changing the user's password or providing authorization codes to other third parties.
Also make sure that this endpoint can't be used by malicious third parties. For example, you can check that the redirect URL provided matches what is expected, since this is where the authorization code will be sent to.

Related

Is there any OpenID Connect Identity Provider that can delegate autentication to other OpenID Connect IdPs?

I'm facing the following scenario:
There are several companies each one with its own OpenID Connect Identity Provider (IdP) which federates users from their respetive LDAP servers. These providers are used to perform SSO in the context of each company.
There's a requirement to create an application that offers a common login for all the users of those companies.
The idea is to provision or use an existing cloud solution (AWS Cognito, Google Cloud Identity, etc., ...) that offers a shared login screen but delegates/federates the actual login to each of the company IdPs.
Are there any solutions that allows this?
Could you point at any documentation/guide to implement it?
This is just standard OAuth and OpenID Connect behaviour, with these 3 roles:
Application, uses OIDC to redirect to ...
An Authorization Server, which you own, and which redirects to ...
An Identity Provider
So you need a standards based authorization server and to configure your app as an OAuth Client. Then include the openid scope so that OpenID Connect is used. SAML based identity providers can also be supported in this flow, even though your app only uses OIDC.
The way to manage this with best usability, is for the authorization server to present a usernane authenticator, which captures a user identifier first, such as an email. It then runs some custom logic, such as a user lookup, to determine which IDP to route the user to. The user then authenticates at the IDP.
After authentication, the IDP issues tokens to the authorization server, which validates them, then issues its own tokens to the application. In particular the app gets an access token whose scopes and claims you can control. Your app can then send these to your APIs, which can authorize access to business data correctly.
Aim for behaviour similar to that above, or adjust it based on your preferences. Then trial it, eg with a cloud or Docker based authorization server, and ensure that you select one with sufficient extensibility to meet your requirements.
Note also that Stack Overflow answers should not recommend particular vendors, so I have not done so.
There is a solution called cloudpods using which you can manage both on-prem and public cloud resources. Cloudpods supports integration with multiple cloud providers like aws, GCP, azure, alibaba and etc.,
Is there any OpenID Connect Identity Provider that can delegate autentication to other OpenID Connect IdPs?
Yes. https://github.com/apereo/cas is one. You can set it up as an OIDC identity provider and have it then delegate to as many OIDC Identity providers as you want.

Token exchange grant support in AWS Cognito

I am working on a cloud native microservices based application deployed in AWS. This application should use a OIDC based IdP (preferably AWS Cognito). The authentication and authorization flow are as follows. Once the user logs in using authorization code flow, the IdP generates one ID token and access token. The access token is sent to the backend services for the backend calls. The backend service can fetch the user information through /userinfo endpoint if needed. Additionally, the access token has the required group claim and the scopes to determine if the right access is present.
Now if the backend service needs to call downstream backend internal microservices on behalf of the logged in user, then should I create a
new token with client credentials grant with a reduced scope needed for the service call? or
Should I send the initial access token of the user only?
In the first case the user context is lost in the new access token and if the downstream service requires the user context, then how will the downstream service get the user information?
In the second case the downstream service is not called with the exact specific scope needed for that service and is not security best practice.
However, there is also one more grant call exchange grant (https://www.rfc-editor.org/rfc/rfc8693.html) which supports creating a new access token with the user context from the initial token without relogging in the user (delegation mode in https://www.rfc-editor.org/rfc/rfc8693.html). Is it supported in AWS Cognito? If not, then how can I achieve the same functionality if I use AWS Cognito?
It kind of depends on the level of trust between microservices. By default, if they are part of the same unit, aim for this type of setup:
Orders microservice, requires an orders scope
Shipping microservice, requires a shipping scope
Customer website, uses scopes orders and shipping
You can then flow the user identity securely, if Orders calls Shipping, by forwarding the access token. Meanwhile each API verifies the JWT on every request and checks for the scopes it needs.
Each API should also check for an audience claim has the expected value, representing a set of related APIs, such as api.example.com. I believe currently though, AWS Cognito does not issue an audience claim to access tokens.
If Shipping is a less trusted subdivision of your company, token exchange would be more appropriate. Eg if you have concerns about a Shipping service abusing Orders privileges.
Avoid over-reliance on scopes, or too many of then. Use claims for the main authorization. In Cognito you can look up these values after verifying the JWT but before your API creates its claims principal
Cognito only has quite limited support for more advanced token behaviour, such as issuing custom claims, reference tokens, or token sharing techniques. If you need them, the preferred option is to choose an authorization server that supports the standards.

Does Google Cloud API support MFA/2VS authentication?

I wanted to know if GCP supports multi-factor authentication (MFA) or 2-Step Verification (2SV) for cloud API calls.
From this link: https://cloud.google.com/docs/authentication, I read the following:
"Google Cloud APIs only accept requests from registered applications, which are uniquely identifiable applications that present a credential at the time of the request. Requests from anonymous applications are rejected.
Application credentials provide the required information about the caller making a request to a Google Cloud API. Valid credential types include API keys, OAuth 2.0 client credentials, or service account keys."
However, it does not specify if I can use these factors simultaneously.
Thanks in advance,
Vijay

Authorization in Google Cloud Endpoints for external clients

We are developing an API which is intended to be used by our external clients which are not inside Google Cloud.
It seems that Google Cloud Endpoints is a good candidate for such case.
What we need:
Client to be able to register in our "developer portal" to obtain necessary credentials.
To keep track of our clients (to see the number of requests of a particular client, to revoke his access to API, etc.)
The part which is not very clear to me is how to authenticate and identify our clients if they are not in Google Cloud.
We already use Firebase authentication by user email in one part or our application. It would be handy to continue using that authentication, but I am not quite understand how.
Google docs say that client application must send a JWT token. But what private key does it have to use to sign the JWT?
The second option to authenticate client we are thinking of is to use custom method to authenticate users. But I have the same question: What private key does the client application have to use to sign the JWT?
Is it intended that client generates its' own key pair?
If there are some better options for our use-case or if I am missing something, feel free to point me in the right direction.
You are on the right way!
With firebase, the JS library allow you to authenticate to the correct identity provider and the lib also allows you to generate a JWT. No private key needed here!
With custom method, it's different. Cloud Endpoint need to validate the signature of the JWT. For this, Cloud Endpoint need to know the public key of the private key used to sign the JWT. Most of time, it's provided by your own IdP system.
In your context, Firebase auth (or Cloud Identity Platform, if you want to manage your users on Google Cloud) is the best solution for you. With several customers, you can't register all their public keys, the only one solution is to have your own IdP and all your customer registered on it.
I have additional question: How do you plan to count the number of request per client? Through Cloud Endpoint or you own database?
We came up with a solution using custom method to authenticate users:
We implemented user authentication by email using firebase (as stated in my question).
Added a way for users to upload their public certificate to our "portal".
2.1. This was done using Google Cloud functions. Basically, we created a two endpoints:
2.1.1. to upload public certificate using firebase token.
2.1.2. to display all public certificates in JWKS format by some url (this way google is able to verify users JWT signature)
Published an instruction for users on how to form JWT to use our API (at this point every user have to have private key associated with their public key uploaded earlier).
Now users of our API are able to make API calls with JWT token provided.
Our technologies stack looks like following:
Cloud functions (for certificate handling).
Firestore (for authentication, storing certificates etc.).
Cloud Endpoints with ESPv2
Google App Engine standard environment

Getting Google IdToken for service account?

I have a backend that is serving android clients, authenticating them with IdToken sent from the android app.
Now, I need to authenticate a service running on aws that is using my apis. So I figured a service account would do the trick, using the private pem file to create a IdToken and send it along just as the android clients do. But I find no way of obtaining an IdToken with these credentials. Is this possible (preferrably in nodejs).
Or am I on the wrong path here?
I know this is older, but I found this question and it didn't lead me to the answer I ended up with.
I followed the guide in https://cloud.google.com/endpoints/docs/openapi/service-account-authentication#using_a_google_id_token with some mix of https://cloud.google.com/iap/docs/authentication-howto, which mentioned that the key to this was to include a target_audience claim in the generated JWT.
So, essentially I made a JWT that looked like:
{
"exp": 1547576771,
"iat": 1547575906,
"aud":"https://www.googleapis.com/oauth2/v4/token",
"target_audience": "https://example.com/",
"iss": EMAIL OF SERVICE ACCOUNT
}
and posted that to https://www.googleapis.com/oauth2/v4/token with params grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer and assertion=<THE JWT>
Without target_audience the endpoint gave me an access token, but with it I got an id_token instead.
Grettings since 2020
I had problems in Java for take ID_TOKEN of a Google Service Account. My project had two years and i were using GoogleCredentials, fromStream method and a JSON credential, but this class didn't gave me ID_TOKEN, only access_token on a not JWT format.
I solved because on this years Google updated here java code for authentication, for take ID_TOKEN you must use this library https://github.com/googleapis/google-auth-library-java
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-credentials</artifactId>
<version>0.20.0</version>
</dependency>
And then use ServiceAccountCredential
String credPath = "/path/to/svc_account.json";
ServiceAccountCredentials sourceCredentials = ServiceAccountCredentials
.fromStream(new FileInputStream(credPath));
When you create this class, itself will authenticate with google and have a access_token,refreshToken...
For extract ID_TOKEN you must use this function:
String audience = "http://localhost"; //Your server domain
IdToken idToken = credential.idTokenWithAudience(audience, new ArrayList<IdTokenProvider.Option>());
String id_token = idToken.getTokenValue();
And with this you have a JWT token.
I hope this help people like me,that are trying get ID_TOKEN.
You cannot use service accounts generated for Google Cloud APIs to directly authenticate against your own APIs. How will you know which service account private keys are valid and which have been revoked? Google does not expose this information.
Service accounts are rather meant for delegation of credentials. When you access Google Cloud platform service, you will be authenticating with your google account credentials. You will not want to provision the very same credentials everywhere your running code needs to access any of the Google cloud services (i.e. Cloud APIs). Instead you create service accounts whose scope can be reduced to a subset of the scope of your google account credentials. This way a particular piece of code can be limited to only a few set of APIs.
Service Accounts
A service account is a special account that can be used by services
and applications running on your Google Compute Engine instance to
interact with other Google Cloud Platform APIs. Applications can use
service account credentials to authorize themselves to a set of APIs
and perform actions within the permissions granted to the service
account and virtual machine instance.
What are service accounts?
Service accounts authenticate applications running on your virtual
machine instances to other Google Cloud Platform services. For
example, if you write an application that reads and writes files on
Google Cloud Storage, it must first authenticate to the Google Cloud
Storage API. You can create a service account and grant the service
account access to the Cloud Storage API. Then, you would update your
application code to pass the service account credentials to the Cloud
Storage API. In this way, your application authenticates seamlessly to
the API without embedding any secret keys or user credentials in your
instance, image, or application code.
I know where your confusion stems, it is because service account also have the same OAuth model you are used to.
You can use service accounts to get access tokens and refresh them as needed, but the scope of authentication is at the very maximum limited to the surface of the Google Cloud APIs. You will not be able to mix and match your APIs with that.
Alternative is to either build your own authentication model (which is not so clear from your question when you say authenticating them with IdToken sent from the android app) or rely on something like Cloud endpoints which you create and manage APIs along with API keys for authentication.
As you already mentioned in one of your comments, you can follow the Service-to-Service authentication guide which describes how you can use Google Cloud Service accounts to authenticate with your APIs running on Google Cloud Endpoint.
It supports using Google ID JWT tokens. The caller will have to send the JWT to Google Token endpoints to obtain a Google ID token and then use this Google ID token in all of your requests. This approach also has the advantage that you only have to whitelist the Google ID token server in your API configuration.