I have a frontend app which I want to connect with a Cognito User Pool.
I am using openidconnect playground to test the authentication flow and this is my Cognito configuration:
I have not put a client secret because I don't think it is safe to have the client secret in the frontend URL.
This is the app client settings:
Using Authorization Code Grant due the rest needs a client secret.
So, this is the URL to do the login:
https://myuserpoolname.auth.eu-west-1.amazoncognito.com/oauth2/authorize?
client_id=YYYYYYYYY
&redirect_uri= https://openidconnect.net/callback
&scope=openid customscope/router customscope/modem
&response_type=code
&state=2282ed48ec2fc0eb0806a532f2eQQf02d0918949
After that, for the exchange to get the token I use this request:
POST https://myuserpoolname.auth.eu-west-1.amazoncognito.com/oauth2/token
grant_type=authorization_code
&client_id=YYYYYYYYY
&redirect_uri=https://openidconnect.net/callback
&code=bd105ab3-Z-X-Y-6109170d1e46
But if I don't share the client_secret as param it returns an error.
How can I do the authentication process without the client secret? Is that possible?
If not, how can I manage the client secret to avoid to manage it in the frontend application?
Thanks.
When using auth code grant type on public clients, you should use PKCE.
Related
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.
I would like to create an integration with quire.io, which currently only supports the Oauth2 authorization_code flow with client_secret.
This causes me a problem because my application will need a dashboard so users can configure it.
So far I have been trying to get a token on a backend server (which has the secret) and then send the token to the client in a cookie as a JWT.
Is there a way I can securely access the quire api from my frontend?
The authorization_code flow without client secret hasn't been implemented yet (different priorities).
For now you'll need the extra server to keep the client_secret in a secure place.
We are running an application via Remote Desktop Services. The application authenticates to our web api middleware running in under WCF using Negotiate and Windows Auth.
We now have a scenario where the middleware needs to make calls to another service and pass a bearer token so that it can run as the user who made the initial request. It would also enable us to not have to use Negotiate on every request, which is fairly expensive.
We're looking for a way that we can make a OAUTH grant_type = client_credentials, but using the credentials of the user which is authenticated via Negotiate to our middleware. I haven't seen any examples of how that would be done. All of the examples I see pass the users credentials via client_id and client_secret, or in the HTTP Basic Auth header, but no examples of grant_type = client_credentials, where the credentials are via Negotiate.
Getting a token as the user without the user interactively logging in via OAuth is generally not supported since the password is unknown.
Aim for option 1 below:
Use client credentials, then pass the user id in addition via a different parameter, such as a path segment - simplest option is to get the downstream service to support this
Login via OAuth and federate to an Identity Provider that uses windows auth - this is likely to be a very big migration job - though it is the preferred way to use OAuth with Windows auth
I know how OAuth2 and OpenID Connect works. But there is still some confusion bothering me.
We develop our own Auth Server, service API and mobile app. So, the client app is trusted and we use "password" grant type. The app user repository follows the same user database in auth server.
Our customers login to the app by username/password. The app then submits the user credential to the Auth Server token endpoint, which will return the (bearer) access token and ID token (JWT) to the client.
The ID token contains basic user information so that the app can greet user like "Welcome Tony Stark!".
The access token can be used to access API (e.g. update user profile).
OAuth by design is not a tool for authentication. Ref: https://www.scottbrady91.com/OAuth/OAuth-is-Not-Authentication
My questions are
1) Do we need to verify the signature of the ID token if the client only is only interested to get the user information? Also note that the ID token is coming from the token endpoint via https connection.
2) Let's forget about the ID token. Can we treat the user has passed the authentication check (i.e. login success) if the client obtains an access token from the Auth Server? This flow is very similar to simple password login without OAuth.
3) The client can access protected APIs with the access token. Without access token, the client can only invoke some public APIs. Is it equivalent to what can be done with and without login? It seems the access token can be treated as "login session cookie".
4) There is no 3rd party involvement in my case. Everything (client, auth server, service API) is developed and owned by the same organization. Does it still make sense to use OAuth?
Typically a mobile app is considered a public client. Unless you're limiting who has access to the mobile app, it can't be considered trusted as someone could mess with the app outside of your control even if you developed it.
Also, the resource credentials grant type is generally not a good idea.
One thing is that the OpenID Connect spec requires authorization code, id token, or a hybrid flow:
Authentication can follow one of three paths: the Authorization Code
Flow (response_type=code), the Implicit Flow (response_type=id_token
token or response_type=id_token), or the Hybrid Flow (using other
Response Type values defined in OAuth 2.0 Multiple Response Type
Encoding Practices [OAuth.Responses]).
Some other reasons:
Why the Resource Owner Password Credentials Grant Type is not Authentication nor Suitable for Modern Applications
The OpenID Connect RFC says you MUST verify the ID token:
When using the Implicit Flow, the contents of the ID Token MUST be validated in the same manner as for the Authorization Code Flow, as defined in Section 3.1.3.7, with the exception of the differences specified in this section.
Although, you may qualify for this exception from 3.1.3.7 if using TLS:
If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
If you're able to trust the client, and the user/pass check you've implemented, then you should be able to trust that an access token has been granted to an authenticated identity according to the OAuth 2.0 spec.
The access token in OAuth 2.0 also contains scopes and should limit what can be done with that access token. A login without OAuth doesn't necessarily.
It's a good idea to use OAuth to protect the credentials of the resource owner. If you were to use the resource owner credentials grant type, this still provides some benefits as the user could enter the password only when the client doesn't have a valid access token, ie, the user can enter her password once for an access token and validate the user using that instead of entering the password again or storing it somewhere.
Even though this grant type requires direct client access to the
resource owner credentials, the resource owner credentials are used
for a single request and are exchanged for an access token. This
grant type can eliminate the need for the client to store the
resource owner credentials for future use, by exchanging the
credentials with a long-lived access token or refresh token.
OAuth 2.0 RFC6749
1) Do we need to verify the signature of the ID token if the client
only is only interested to get the user information? Also note that
the ID token is coming from the token endpoint via https connection.
YES.
2) Let's forget about the ID token. Can we treat the user has passed
the authentication check (i.e. login success) if the client obtains an
access token from the Auth Server? This flow is very similar to simple
password login without OAuth.
If I understand the premise. Yes..There is no requirement for using the ID Token.
3) The client can access protected APIs with the access token. Without
access token, the client can only invoke some public APIs. Is it
equivalent to what can be done with and without login? It seems the
access token can be treated as "login session cookie".
The access token is a access (like a key) that for the OAuth Client to use that was delegated permissions from the resource owner.
4) There is no 3rd party involvement in my case. Everything (client,
auth server, service API) is developed and owned by the same
organization. Does it still make sense to use OAuth?
Yes. OAuth and OpenID Connect are used by many, many organizations and is a test solution.
You should not try to re-invent the "wheel". Use known trusted libraries for Authentication, Authorization and cryptographic operations. OpenID Connect has some certified Implementations
The model for our product is like this:
Api backend (headless)
I already have oauth set up and ready to use with a resource owner credentials grant. Anyone who wants to use our api can do so using either an API key or their username/password. Of course they also need their client ID and secret.
SPA frontend that accesses the Api
I have built an SPA that will uses the api to provide a portal GUI for our clients. Given that this client-side app is owned and administrated by us (so it's a trusted app) how can I safely authenticate users using only username/password with oauth?
Originally it was using a JWT auth system that only required username/pass but now that we've implemented oauth I'd like to consolidate. It's unreasonable to make every user need to also have their client id and secret on hand to login, but I want users to have full access to the api from the GUI.
I've looking at using CSRF tokens but how would that work with my app when nothing is generated server-side?
I'm not sure how to proceed.
EDIT: very similar to the problem here.
I have decided to use the solution described here.
And here is a snippet of my implementation
The TL;DR version is
Create a proxy between the app and the api
Store the client ID and secret in the proxy
App logs in using password grant type -- proxy intercepts login request and inserts client id and secret
On login response proxy returns access token as an encrypted cookie
Client stores cookie and sends with api requests (to proxy)
Proxy decrypts cookie and inserts access token into Authorization header before forwarding to api endpoint
For me this has several advantages over implementing something custom on the api itself:
No need for custom grant on oauth server
ID/secret is hidden from app securely and can still use password grant
oauth server can identify client (no need for separate client ids for each user)
You should not use the resource owner credential grant from a JavaScript application. The fact that you own and administer the application does not make it a trusted application.
A trusted client is an application that can keep a secret. SPAs or any JavaScript app cannot keep a secret.
You should use the implicit grant for non-trusted clients.