Can I federate Cognito with "client credentials" flow (or other way to trust a server-side application authenticated elsewhere?) - amazon-cognito

I have an AWS REST API Gateway with Cognito authentication using the client credentials grant.
We have been creating new clients by hand and sharing the ID/secret with people who need to use our API. They send the ID/secret and "grant_type=client_credentials" to Cognito, it gives them a bearer token and they use the API with the token. All fine so far. (It is a CLI tool running on a schedule, not accessed by a browser. I specifically need to avoid any sort of "go to the browser to login".)
Now, we have a new "island" of users who have a local OIDC (Azure AD) provider that can issue them a bearer token from a curl to an endpoint.
Is there a way to make Cognito accept those tokens??
I have tried federating Cognito with a different oidc provider (I don't have AD, but a different provider), getting myself a bearer token from it and sending it to the API GW, and I just get 401'ed. I don't know if there is something I'm doing wrong or if it's not possible.
(Things I might be doing wrong seems to be a long list! I need to create a client in the other provider and add it's ID/secret/URL to Cognito, that works. I used the same client ID/secret to generate my bearer token. But when I'm in client creds flow in Cognito, I need to set a custom scope. Do I need to add that scope to my initial request to the other provider (The API GW doesn't require a scope, it is just a mock endpoint at the moment in testing). The client_id= in the request is for the client in the other provider, not the Cognito client ID. Should I set it to the Cognito client ID?)
OR do I need to write a custom authenticator for the API GW to validate the token? (Decode JWT, Check : issuer is allowed and signature is valid.)
And not use Cognito at all for these other users.
(If it was an HTTP API, I think I can create a JWT authoriser and it does it all for me, but it isn't and there are some features on REST APIs not available on HTTP (like WAF))
Sorry it's a bit short on details. I could spend days copy/pasting all the configs from ID provider/Cognito but if it fundamentally won't work I wasted my time!
(After trying it, I think maybe federation only works for actual users with a browser based login flow, not clients with a CLI flow. I can't find anyone saying client credentials flow does work anyway!)

Cognito is using the authorization server role. So in all cases, the tokens returned to client applications will be issued by Cognito. These apps will never deal with Azure AD tokens. Multiple types of client can coexist together:
CLIENT CREDENTIALS GRANT
Clients who use this flow might represent B2B connections. The business partner must always get Cognito tokens directly, and no federation is used here.
AUTHORIZATION CODE GRANT
Browser clients will use this flow, and you can configure Cognito to implement authentication by making a second OIDC Connect redirect to Azure AD.
My blog post provides a walkthrough on how settings are configured. Cognito will act as a client of Azure AD and use a scope such as openid profile email.
After a user login, Cognito will receive Azure AD tokens, validate them, then issue its own tokens. Nothing will change in the API gateway, which will continue to verify Cognito tokens.

Related

When an Oauth provider is used to delegate authentication, then does the appserver return any token to the caller?

In Oauth and Openidconnect, the appserver endpoint invocation starts the Oauth flow and the app server gets the token from the auth server and is able to pass the token to resource server to access resources (delegation) on behalf of the resource owner.
The token exchange happens between the app server and resource server, and the token never arrives at the end users browser.
I'm working on a web api (aka app server) that will be consumed by a mobile app. There is no other server involved. Presently the login endpoint returns a signed JWT token to the user if correct credentials are supplied (validate against the db). User places this token in the header of the subsequent request.
Assuming I don't want to have a user db and validate logins, and instead delegate the auth check to another service like azure b2c or firebase (that use the Oauth), then I assume the flow is like given below:
Api registered the firebase/azure b2c (let's call this the provier) clientid, secret.
User invokes login endpoint of my api
The api invokes the provider's Oauth flow.
User gets popup to authenticate with the provider.
Eventually the provider will send the token (containing the claim like username) to the api (aka app server)
Does the user get back any token? Otherwise, when the user makes subsequent endpoint calls, then how is the endpoint able to identify who is this user and whether he is already authenticated?
Although it is okay to send back the access token to the user , but from the security best practise 's point of view , it is better not to do it which I quote the reasons as follow from this:
Because of the issues outlined above, the best security recommendation
for an SPA is to avoid keeping tokens in the browser at all. This can
be achieved with the help of a lightweight back-end component, often
described as a Backend-For-Frontend.
The backend component can then be configured as a confidential OAuth
client and used to keep tokens away from the browser. It can either be
stateful and keep tokens in custom storage, or stateless and store the
tokens in encrypted HTTP-only, same-site cookies. Whichever variant is
chosen, the backend component creates a session for the SPA, using
HTTP-only, secure, same-site cookies, thus enabling a high level of
security. Such cookies cannot be read by scripts and are limited to
the domain of the SPA. When combined with strict Content Security
Policy headers, such architecture can provide a robust protection
against stealing tokens
Also from here ,they suggest for mobile app 's OAuth2 best practise , it should perform the OAuth flow inside a system browser component.

Securing an API with SAML SSO / OAuth2.0

Alright, so I'm having a hard time understanding a proper flow here for my setup.
Goal
I want to have a proper SSO flow for my SPA app that can authenticate users into an API.
Context
I have a React application that is intended to use an Okta porta that offers both SAML (preferred) and OIDC for SSO flows. I've wrapped my static sources in a web server that serves them, and that server has a middleware that checks for cookies, and if one doesn't exist, I redirect to the IDP (Okta) for login. This all works fine for now.
Currently, my API sits on that same server, which I intend on moving to a separate server to scale independently of the website. My API must also allow other machine clients (services) to call into it, so I implemented a service account flow that uses client ID and secret as the authentication measure.
In general, my intended flow looks like this:
User navigates to my website (unauthorized) -> Web Server -> Redirect to IDP -> Assertion Callback flow -> Generate JWT session cookie -> Web Application makes API call -> API Server auth middleware validates cookie / bearer token.
The problem.
The details of how the JWT access token is generated is where I'm stuck. Currently, my webserver receives the SAML assertion and generates a JWT, which is not the same JWT claims logic as the service accounts (bleh). I'm thinking of implementing an Auth service instead to centralize the token generation flows.
For the Auth Service, I've looked into OAuth2.0 and it seems like just the right approach for what I need. With that said, I can't find much information on patterns to follow for SAML assertion -> OAuth2.0. I saw an IETF draft for saml2-bearer grant-type, but it seems dead in the water. I'm also unsure about the general consensus on custom implemented OAuth2.0 grant types.
What does a proper flow look like? I have a couple of scenarios in mind:
SAML Service Provider within the same service as the Auth
Service. On lack of SSO session, my application redirects to my Auth service, which then redirects to my IDP. The IDP calls my SP (the auth server) with the assertion, the auth service generates a token, then my auth service redirects back to the webserver with a cookie placed in the response headers.
SAML SP as the webserver Since the webserver is the only system that needs to use the SSO, I could just keep the SAML flow within that process. Once my webserver receives the SAML assertion callback, my server makes a call to an endpoint service with the assertion claims, and then my auth service returns the access token in a JSON response.
Something else, like OAuth2.0 authorization code flow with PKCE for the web application. Or OIDC instead of SAML for SSO.
OIDC sounds like the right choice for you as APIs are involved. OAuth is designed to secure APIs' compared to SAML which is built for enterprise SSO.
You can integrate your SPA with Okta using OIDC. Okta provides SDK's for varies platforms to make it easier for you to do so. You can find SDKs' here:
https://developer.okta.com/code/angular/okta_angular_auth_js/
Once you get an ID token and Access token from Okta after OIDC flow, you can use the access token to access external API's. Your API resource server or the API gateway can validate the access token. Again Okta provides SDK's to verify access tokens: https://developer.okta.com/code/dotnet/jwt-validation/

identityserver4 protect public api

I am using identity server 4, I followed the tutorial, so I have an api, mvc client, console client, and js client.
I saw this blog too, which is probably close to what I need:
https://medium.com/all-technology-feeds/testing-your-asp-net-core-webapi-secured-with-identityserver4-in-postman-97eee976aa16
what I need is an api, where clients can access data, but first, they need authenticate.
we also have the console client, which is also close to what I need.
The only issue with this examples is that in both cases client knows the secret. But in our case multiple clients should use the same api, and if they all have the same secret, they can log in on behalf of each other, but I don't want to have different secrets.
So what I think I could do is to create an api which takes username and password, and returns the token. But I am not sure if this is the right way to do things? This feels like a resource owner flow, which is not supposed to be used for client facing APIs if I am correct. But in that case, how should I go it?
thanks
It seems that there is some confusion. Allow me to give a short summary. First the terminology:
A user is a human that is using a registered client to access resources.
A client is a piece of software that requests tokens from IdentityServer - either for authenticating a user (requesting an identity token) or for accessing a resource (requesting an access token). A client must be first registered with IdentityServer before it can request tokens.
Resources are something you want to protect with IdentityServer - either identity data of your users, or APIs.
Client credentials: The simplest grant type and is used for server to server communication - tokens are always requested on behalf of a client, not a user.
Now about authentication. The client requests tokens at the IdentityServer endpoint. When you use a client in combination with the client credentials flow, then you'll need a clientid + secret. Where secret is really secret and should be known to the client only. You can't use the same secret here. Seems logical when compared to users, they don't share the same password either.
This is close to the resource owner flow, however a client cannot login as a user. For that you'll need another flow, like the hybrid flow. In that case the client logs in on behalf of the user. The difference is the presence of the "sub" claim (the id of the user) in the token.
The client in this case is your app: console or mvc. The first only supports client credentials where the secret is mandatory, the second supports a hybrid flow, where secret may be omitted:
In certain situations, clients need to authenticate with
identityserver, e.g.
confidential applications (aka clients) requesting tokens at the token endpoint
APIs validating reference tokens at the introspection endpoint
The Api is your resource, that you want to protect. The Api never authenticates a user or client. This is done by IdentityServer. It only verifies the token (using the IdentityServer4.AccessTokenValidation package). For that it has its own secret that should only be known to the Api.
In order to grant the client access to the resource you'll need to add the scope to the client in the configuration of IdentityServer. The client is then allowed, not required, to request a token that grants access to the resource.
Again, the Api has nothing to do with authentication. It is also not bound to one client. Multiple clients can access the resource. All you have to do is add the scope to each client that should have access to the resource.
So there is really nothing against it that clients and resources know their secret. You don't have to change anything. All you have to do is choose the appropriate flow.

OpenId Connect renew access_token in SPA

Trying to implement OpenId Connect in Web Application consisting of following components
Identity Provider
Resource server
Single Page Application acting as Client.
Identity Provider and Resource Server are the same application.
SPA use Password Flow to get access_token and stores into the cookie. Storing access_token into cookie has it's security threads, but's it's a different story.
Problem
access_token issued by IdP is expired after 30 min and SPA needs to renew token without asking users for credentials again.
Solution
IdP returns refresh_token along with access_token. Whenever SPA gets 401 from Resource Server, it sends refresh_token to IdP and get's new access_token back.
Problem
Sending refresh_token to SPA is bad practice.
A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a Refresh Token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials since a Refresh Token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.
Suggested solution
When the Access Token has expired, silent authentication can be used to retrieve a new one without user interaction, assuming the user's SSO session has not expired.
I think Silent Authentication is not applicable to Password Flow when IdP and Resource Server is same application. access_token issued by IdP is only piece of information which can be used to authorize against Resource Server/IdP after its expiration, how a client can convince IdP to issue new access_token? (without sending refresh_token)
Found angular-oauth2-oidc library which uses refresh_token to renew access_token.
What is best practice/solution in this case to renew access_token?
technical details
Identity Provider - ASP.NET Core + Openiddict library.
SPA - AngularJs application.
Single page applications must not receive refresh tokens. That has been established rules in OAuth 2.0 and OpenID Connect.
One good option I see here is to use Implicit Flow. This will establish a front channel session from your browser to Identity Provider. With password grant type you do a back-channel call (POST), so you don't get such session.
Usually this is a cookie which points to information about previous logged in status (these are identity provider specifics). With completion of the flow, SPA will receive the access token. As you figured out, it will expire. But once that happens, SPA can trigger another implicit flow, but this time with prompt query parameter.
prompt
Space delimited, case sensitive list of ASCII string values that
specifies whether the Authorization Server prompts the End-User for
reauthentication and consent. The defined values are: none , login, consent and select_account
If you identity provider maintain a long lived session (ex:- few hours or days) or if it maintain a remember me cookie, SPA could use prompt=none making it to skip login step from identity provider. Basically, you are getting browser based SSO behaviour with this.
Using the Resource Owner Password Credentials flow defeats the refresh token storage argument: instead of not being able to store the refresh token in a secure place, the SPA would now have to store the Resource Owner credentials in a secure place (assuming you want to avoid requesting username/password from the user frequently). The Implicit grant was designed for usage with an SPA, so it is better to stick with that.
Further to previous answers, the latest OAuth working group guidance for SPAs no longer recommends use of the implicit flow.
If you have simple, shared domain app (IdP, RS and client on a single domain) then you should consider not using OAuth at all. From the doc:
OAuth and OpenID Connect provide very little benefit in this
deployment scenario, so it is recommended to reconsider whether you
need OAuth or OpenID Connect at all in this case. Session
authentication has the benefit of having fewer moving parts and fewer
attack vectors. OAuth and OpenID Connect were created primarily for
third-party or federated access to APIs, so may not be the best
solution in a same-domain scenario.
If you are using OIDC/OAuth in a SPA, they recommend the auth code flow with PKCE.

How to combine user- and client-level authentication in an API gateway?

We're looking to implement web (external user) SSO and an API gateway to support web apps and mobile apps, and potentially 3rd party apps and even B2B scenarios.
My thought is to have the SSO gateway handle user-level access to websites and APIs, authenticating end users using OAuth or OpenID Connect.
Sitting behind this, for any API URLs, is the API gateway. This is intended to handle the client-/application-level authentication using something like a client ID and secret.
The idea would be that the user would log into a website or mobile app, and then if/when that app needed to call an API it would need to send its own credentials (client credentials flow) as well as a bearer token proving who the user is as well (resource owner password flow).
The client credentials are less about security and more about coarse-grained access to API functions, giving visibility of API usage, traffic shaping, SLAs etc., but the user identity is needed to enforce data-level authorisation downstream.
Most API gateways I've looked at appear to only support a single level of authentication, e.g. we're looking at Apigee at the moment that can use OAuth to authentication to handle either a user or an app, but it's not obvious how to do both at once.
Is there any way to get the SSO gateway's user bearer token to play nicely with the API gateway's client bearer token or credentials, preferably in a fairly standards-based way? Or do we just have to hack it so that one comes through in the auth header and the other in the payload? Or is there a way to have a combined approach (e.g. hybrid bearer token) that can serve both purposes at once?
I'm kind of surprised that with all the work going on in identity management (OAuth2, OpenID Connect, UMA, etc.) nobody is looking at a way of handling simultaneously the multiple levels of authentication - user, client, device, etc.
Unfortunately I don't have enough reputation points to comment on the previous post, so I'll add my two cents here. Full disclosure: I work for Apigee.
http://apigee.com/docs/api-services/content/oauthv2-policy#accesstokenelement explains how to give the access token to the Apigee OAuthV2 policy in a place other than the Authorization header. If you've stored the SSO bearer token as an attribute of the Apigee OAuth token then once the Apigee token is validated you'll automatically get the SSO bearer token as a flow variable and can use it as needed.
For example, if you send the token as a "token" query parameter on the request you can code the following in the OAuthV2 policy
request.queryparam.token
and the policy will pull it from that query parameter.