Questions about Native applications and openId Authorization code flow - react-native

I have a few concerns with an OpenId Connect strategy that I would like to use and have been unable to find specifics on what the security concerns may be and any glaring issues with it I am overlooking.
Currently, I have an OpenId Connect implementation using Openiddict with Authorization Code flow. For the client, I have a React-Native app using react-native-app-auth.
I see from other questions on SO and from issues posted on the Openiddict repo that the recommended approach to third-party providers (e.g. Google) is: Client -> Auth server -> Google Auth -> Auth server -> Client/Auth server code and token exchange
However, it seems that a better approach from a UX standpoint (when using a SPA or native app) would be to implement something similar to GoogleSignIn on the client and either handle the identity on the server using an IdToken or authorization code from Google. This introduces an issue as the flow previously recommended could not be used as the entire initial challenge and redirect from Auth server to Google Auth has been skipped.
I have seen that this issue is mitigated by not using the authorization code grant and instead implementing a custom assertion grant. This seems to be an alright approach but would require exposing a custom grant and handling the flow differently on the client and server for local and third-party logins.
My proposed solution continues to use the authorization code flow and instead of adding a custom grant type the client could just pass a third-party identifier "Google" and the token or authorization code in the additional parameters of the OIDC authorize request. The authorize endpoint could then detect the provider and token, perform token validation, create a user or principal from it, and create an authorization code to send back to the client for the code/token exchange. This flow would look like the following:
1. Get the id token from the provider Client -> GoogleSignIn -> Client
2. Pass token to auth server and initiate code / token exchange Client -> Auth Server -> Auth server Verify Google IdToken (JWKS, issuer, audience, provider specific validation, etc...) or exchange auth code -> Auth server -> Client/Auth server code and token exchange
One downside to this approach would be the additional hops to verify the token on the server side. If the token was returned from GoogleSignIn, they themselves said that it could be trusted. https://developers.google.com/identity/protocols/oauth2/openid-connect#obtainuserinfo
I see that it is generally recommended to place the auth server between the client and the third-party but in this process the server is still between the client and auth server but only after the initial exchange from the client and third-party.
Questions,
In general am I missing something with this flow?
In this case would it be necessary to verify the token on the server side?
Is there some better way to approach this that I have completely overlooked?
Am I making this too complicated and UX should not be this much of a concern?
Instead of adding the provider and token to the additional parameters would it make more sense to pass it in the body of a post request? I don't see the issue with passing it via query string but that's also part of the reasoning for the authorization code grant from my understanding.
Apologies in advance for anything I have missed or omitted for brevity that should have been included.
Thanks.

ARCHITECTURE
I'm not sure I understand the UX problem - your existing architecture feels really good. If you want to login directly to Google, just send an acr_values=google query parameter in the authorization redirect, to bypass any authentication selection screens. The exact value will depend on how Openiddict represents the Google authentication option, and some providers use a non-standard parameter such as idp. Have a closer look at the OIDC request parameters.
A key OAuth goal is that the Authorization Server (AS) - Openiddict in your case - shields your apps from all of the provider differences and deals with their nuances and vendor specific behaviour. Your apps then also only receive one type of token, and only ever use simple code. As an example, the Curity AS supports all of these options, none of which requires any code in applications.
APPAUTH AND UX
If a user is already signed in then it can, as you say, look unnatural to spin up the system browser and them it is dismissed immediately.
A common option is to show the consent screen or an interstitial page to keep the user informed - and the user clicks one extra button. This can also be useful for getting password autofill to work. My code example and blog post shows how this might look, though of course you can improve on my basic UX.
OFFLINE ACCESS
I find this term misleading, since refresh tokens are most commonly used when the user is there. Are you just asking how to deal with tokens in a mobile client? Aim for behaviour like this:
Standard messages for API calls with access tokens in an authorization bearer header
Standard refresh token grant messages to refresh access tokens - eg as in this code
Note also that mobile apps can save tokens to encrypted secure mobile storage that is private to the app. This can improve usability, eg by avoiding logins every time the app is restarted. You should think through scenarios such as stolen devices and token lifetimes though.

Related

How to exchange authorization code on backend/API for Mobile OAuth 2.0 federated log in

I currently am working on a mobile app that uses OAuth 2.0 for federated log in with a custom identity provider (not google, facebook, twitter, etc). The larger issue I am attempting to solve revolves around moving the authentication from the implicit grant type, to the authorization code flow grant type with PKCE. This has presented me with a problem that I cannot seem to find a direct answer to:
How do I exchange the authorization code for the user token on the API/backend side?
I cannot exchange the authorization code for the user token on the mobile app as that would be insecure (similar to the current grant type in use).
Is it safe to pass the authorization code to the API through normal API calls and exchange the auth code for the token then? Or, am I supposed to point the redirect URI to the API instead of the mobile app?
Okay, so I am answering my own question as no one else will due to the fact that my question is stupid.
You don't.
You exchange the auth code for the token on the native app. That is secure (as long as you are using PKCE). You need to send the access token to your API/Resource Server to validate against the introspection endpoint. That is how your API can determine if the access request is valid or not.

What's the proper way to implement a "static" authorization token feature using OIDC (or OAuth2)

I am exploring possible solutions for creating something like "API Keys" to consume my API. The goal is to allow for users to generate one or many "API Keys" from the web app and use the static generated key from the CLI app.
The web app and the client app are already using standard OIDC with JWT tokens for authentication and authorization using RBAC (role-based access control). The CLI app can already authenticate the user through the standard browser flow (redirects the user to the browser to authenticate and exchange the token back to the client).
The "API Keys" solution I am trying to achieve should have some fine-grained options where it won't authenticate as the user, but will authorize the client on behalf of the user (something like the GitHub Personal Access Token).
To me it seems like a "solved problem" as multiple services provide this kind of feature and my goal is to do it the most standard way possible using the Oauth2/OIDC protocols but I can't find details on what parts of the protocols should be used.
Can anybody provide any guidance on how it is supposed to be done using the Oauth2/OIDC entities?
Can I achieve it by only using Role-based access control or do I need Resource-based access control?
It went through the path of creating a new client for each "API Key" created, but it didn't feel right to create so many clients in the realm.
Any guidance or links to any materials are appreciated.
Can anybody provide any guidance on how it is supposed to be done
using the Oauth2/OIDC entities?
OIDC is based on OAUth 2.0 so after user login you have id tokens, access token and refresh token on the backend side. To generate new access token without asking user for authentication data you should use refresh token: https://oauth.net/2/refresh-tokens/
Can I achieve it by only using Role-based access control or do I need
Resource-based access control?
resource-based access control is more flexible solution here, but if you business requirement is not complex, then role based might be enough.
It went through the path of creating a new client for each "API Key"
created, but it didn't feel right to create so many clients in the
realm.
It is one application so you should use one client with specific configuration for access token and roles/permissions for users.
Update:
We can use GitHub as an example:
User is authenticated during login
for OIDC code is exchanged for id token, access token and refresh token
session for user is set for web browser
User can request access token
in GitHub authenticated user can request github.com/settings/personal-access-tokens/new endpoint
request is accepted, because user is authenticated based on session
backend service responsible for returning access token can obtain new access token using refresh token from point 1.
access token is returned to GitHub user
To call your API in an OAuth way, CLI users must authenticate periodically. Resulting access tokens can be long lived, as for GitHub keys, if you judge that secure enough. The access token returned can be used exactly like an API key. There may be a little friction here between usability and security.
CONSOLE FLOW
The classic flow for a console app is to use the Native Apps Desktop Flow from RFC8252. This involves the user interactively signing in using the code flow, then receiving the response on a loopback URL. It is an interactive experience, but should only be required occasionally, as for GitHub tokens.
API KEYS
The access token returned is sent in the authorization header and you can use it as an API key. Access tokens can use a reference token format. to make them shorter and confidential, to prevent information disclosure. These will be more natural in a CLI.
API AUTHORIZATION
When your API is called, it must receive access tokens containing scopes and claims, to identify the user. This will enable you to authorize correctly and lock down permissions.
{
sub: 586368,
scope: repos_write,
topic: mobile,
subscription_level: silver
exp: ?
}
TOKEN REFRESH
Sometimes CLI access tokens are long lived, for convenience. A more secure option is for the CLI to use token refresh. It can then store a refresh token in OS secure storage, then renew access tokens seamlessly. My blog post has some screenshots on how this looks, and a desktop app that does not require login upon restart. The CLI needs to deal with expired access tokens and handle 401 responses.
DYNAMIC CLIENT REGISTRATION
Some developer portal scenarios use DCR. It is another option in your security toolbox. It could potentially enable a silent client per CLI user:
User runs a standard authentication flow with a DCR scope
This returns an access token that enables client registration
The resulting token is used to register a new client
This could potentially be a client ID and client secret used in a CLI
Afterwards, the user and client are bound together. Probably not immediately relevant, but worth knowing about.

How to send a JWT from my back-end server to my front-end after Google OAuth2 Authorization flow

I am creating an application with a React front-end and a Java Spring Boot back-end.
My login flow looks like this:
A user clicks on login on the front end
User is redirected to the Google Oauth authorization endpoint on my server
OAuth 2.0 Authorization flow happens: User is redirected to Google and logs in. Google interacts with my server first exchanging an authorization code and then a JWT access token. My server now has the JWT access token for the user.
ISSUE: I now need to redirect the JWT token to my React front-end so that the token can be saved and used every time the user wants to request access to a protected resource on my server.
Is there now an industry standard/best practice for redirecting the token to my React front-end from the server?
There are similar questions on this subject on Stack Overflow, however they are at least 3 years old, e.g. How to provide frontend with JSON web token after server authentication?
Since then the implicit flow has been deprecated, storing JWTs in local storage is no longer recommended, and https://datatracker.ietf.org/doc/html/rfc6750 explicitly discourages passing bearer tokens to the front end in a redirect URL.
I was wondering if anyone knows of an up to date solution for this problem.
There's a draft IETF BCP for OAuth 2.0 for Browser-Based Apps - see here. Basically, it's very similar to native mobile apps using authorization code with PKCE (proof key for code exchange).
FWIW I agree implicit flow shouldn't be used, but IMO you shouldn't be using authorization code flow without PKCE, as this flow is for server side rendered web apps.
EDIT - Auth0 (one of the most popular CIAM solutions on the market) docs say the same thing - see here.
If the Client is a Single-Page App (SPA), an application running in a
browser using a scripting language like JavaScript, there are two
grant options: the Authorization Code Flow with Proof Key for Code
Exchange (PKCE) and the Implicit Flow with Form Post. For most cases,
we recommend using the Authorization Code Flow with PKCE...
Don't.
You seem to mix 2 issues here.
First, you would like to use OIDC for authentication in your SPA. For this you would use OIDC Implicit Flow or Authorization Code Flow with PKCE.
Second, you would like to delegate authentication to google instead of doing it yourself. Basically this is known as federation - you trust external Identity Provider.
The full-blown version would be to setup your own Identity-Provider server (like e.g. keycloak) and configure federation to google there. Your SPA would initiate OIDC against your Identity Provider and wouldn't even know that google did the authentication. You could also easily add further Identity Providers (e.g. facebook) if necessary.
An easier workaround would be to initiate OIDC login from your SPA directly to Google. This way your SPA would receive token directly from google and you would need to protect your own backend as a resource-server accepting and validating those tokens. Adding further Identity-Providers like facebook would be a challenge.

Oauth 2.0 and OpenId Connect for REST API authentication and authorization

After having read books and watched videos on OAuth, OIDC, PKCE, JWT, etc. I still have no idea on how to use all of these for my app (a secured REST API).
My use case is fairly simple. I want my users to be able to login with Google, Amazon, Okta or whatever and the only info I want from them is the email address they used to login, nothing else. After their first login, their email will be added to a database and in a separate process I will grant them some permissions (what resources they can access).
So let's imagine a standard authorization code flow and let's fast forward to the access token part. The redirect URI has been called, we are in my client (somewhere is my backend/API) where I retrieve an access token. At this point the user has been successfully authenticated.
But what now ?
I don't care about Google anymore (do I still need the access token ?), but I still want to check if the user can use my API for each request and is able to access the API resources depending on his permissions.
How do I keep the user authenticated (for like 2h only) and check his permissions ? A session Cookie, a Token or something else with an expiration time ?
Do I need my own authorization server to check if the user has access to the resource he is requesting ?
Considering my requirements, do I need PKCE if the API is accessed from an SPA or a mobile app ? Wouldn't the authorization code flow be enough - the SPA or mobile app retrieve an authorization code, then call the callback endpoint from the API ?
And the more important question is, do I ask the right questions or am I completely off track and it's not how it's supposed to work ?
In terms of your questions:
Your API needs an access token on every request
A stateless session is managed by sending the access token on every request
It is recommended to use your own Authorization Server that manages redirecting to social providers - this will simplify your UIs and APIs which only need to handle one type of token - also this means you are in control of the tokens your apps use
Yes - use PKCE for public clients - the Authorization Server and UI security libraries will handle this for you
Your use case is not simple at all on a technical level and requires a lot of understanding. A good starting point is to understand these aspects:
Role of UI and what a coded solution looks like
Role of Authorization Server and its configuration
Role of API and what a coded solution looks like
Open Id Connect messages used
These links of mine may be useful for browsing:
Initial code sample and tutorial
Message Workflow including PKCE
Given an access token, both the UI and API can potentially get the email via step 12 in the second link to lookup user info.

Microservice Authentication strategy

I'm having a hard time choosing a decent/secure authentication strategy for a microservice architecture. The only SO post I found on the topic is this one: Single Sign-On in Microservice Architecture
My idea here is to have in each service (eg. authentication, messaging, notification, profile etc.) a unique reference to each user (quite logically then his user_id) and the possibility to get the current user's id if logged in.
From my researches, I see there are two possible strategies:
1. Shared architecture
In this strategy, the authentication app is one service among other. But each service must be able to make the conversion session_id => user_id so it must be dead simple. That's why I thought of Redis, that would store the key:value session_id:user_id.
2. Firewall architecture
In this strategy, session storage doesn't really matter, as it is only handled by the authenticating app. Then the user_id can be forwarded to other services. I thought of Rails + Devise (+ Redis or mem-cached, or cookie storage, etc.) but there are tons of possibilities. The only thing that matter is that Service X will never need to authenticate the user.
How do those two solutions compare in terms of:
security
robustness
scalability
ease of use
Or maybe you would suggest another solution I haven't mentioned in here?
I like the solution #1 better but haven't found much default implementation that would secure me in the fact that I'm going in the right direction.
Based on what I understand, a good way to resolve it is by using the OAuth 2 protocol (you can find a little more information about it on http://oauth.net/2/)
When your user logs into your application they will get a token and with this token they will be able to send to other services to identify them in the request.
Example of Chained Microservice Design
Resources:
http://presos.dsyer.com/decks/microservice-security.html
https://github.com/intridea/oauth2
https://spring.io/guides/tutorials/spring-security-and-angular-js/
Short answer : Use Oauth2.0 kind token based authentication, which can be used in any type of applications like a webapp or mobile app. The sequence of steps involved for a web application would be then to
authenticate against ID provider
keep the access token in cookie
access the pages in webapp
call the services
Diagram below depicts the components which would be needed. Such an architecture separating the web and data apis will give a good scalability, resilience and stability
You can avoid storing session info in the backend by using JWT tokens.
Here's how it could look like using OAuth 2.0 & OpenID Connect. I'm also adding username & password login to the answer as I assume most people add it as a login option too.
Here are the suggested components of the solution:
Account-service: a microservice responsible for user creation & authentication. can have endpoints for Google, Facebook and/or regular username & password authentication endpoints - login, register.
On register - meaning via register endpoint or first google/fb login, we can store info about the user in the DB.
After the user successfully logs in using either of the options, on the server side we create a JWT token with relevant user data, like userID. To avoid tampering, we sign it using a token secret we define(that's a string).
This token should be returned as httpOnly cookie alongside the login response. It is recommended that it's https only too for security. This token would be the ID token, with regards to the OpenID connect specification.
Client side web application: receives the signed JWT as httpOnly cookie, which means this data is not accessible to javascript code, and is recommended from a security standpoint. When sending subsequent requests to the server or to other microservices, we attach the cookie to the request(in axios it would mean to use withCredentials: true).
Microservices that need to authenticate the user by the token:
These services verify the signature of the JWT token, and read it using the same secret provided to sign the token. then they can access the data stored on the token, like the userID, and fetch the DB for additional info about the user, or do whichever other logic. Note - this is not intended for use as authorization, but for authentication. for that, we have refresh token & access token, which are out of scope of the question.
I have recently created a detailed guide specifically about this subject, in case it helps someone: https://www.aspecto.io/blog/microservices-authentication-strategies-theory-to-practice/
One more architecture perspective is to use nuget-package (library) which actually do authentication/token validaton. Nuget-package will be consumed by each microservice.
One more benefit is that there is no code duplication.
you can use idenitty server 4 for authentication and authorisation purpose
you must use Firewall Architecture hence you have more control over secutiry , robustness ,scalability and ease of use