I am currently using OpenID Connect/Oauth2 Implicit Flow in a mobile app. I am bringing up a Web View for the user to login and obtaining the access token and expiry. However, when the access token expires, do I need to ask the user to log in again? Or is there a way to get a new access token silently using the current one, without bugging the user. I guess another option is to set the token expiry to be a really long time, but I have read that this is a bad idea.
Am I missing something here?
Since Implicit flow does not send a refresh token (as explained in section 9 of RFC6746), usage of refresh tokens is not possible. But as a workaround one can use client credential grant to obtain an access token.
A viable solution is to first follow the implicit flow and authenticate the client. Then client authentication grant can be used to do the required API calls.
Sample request (from RFC6749)
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
rant_type=client_credentials
Sample resposne (from RFC6749)
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
P.S -
If you are using authorization code flow, you can use refresh_token to get a new access token. How the request should be formed can be obtained from OAuth2 documentation. Note that to do so, your authorization response should contain a `refresh_token.
A refresh token should be protected as valuable as a credential for a user. More can be read from keycloak documentation from here
Sample request and a response (from RFC6749)
Request
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
Response
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "TlBN45jURg",
"token_type": "Bearer",
"refresh_token": "9yNOxJtZa5",
"expires_in": 3600
}
The recommended way is to use an external browser and the Authorization Code Flow. Check the OAuth 2.0 for Native Apps RFC. For Android, there is also a supporting library AppAuth. With this flow, you can use a refresh token to get a new access token, but there is an issue with a client secret (usually needed for accessing /token endpoint), because you cannot keep it safe in a mobile app (it's described in the RFC).
If you decide to stick with the WebView and the Implicit Flow, which is not safe (your app can see the password) you could use the same technique as in JavaScript applications - request a new token with /auth?...&prompt=none URL which will return a new token without asking the user for credentials if he still has an open session there.
Related
In postman i have set simple request to access Azure DevOps API, using OAuth 2.0 security via Azure AD
https://learn.microsoft.com/en-us/rest/api/azure/devops/core/projects/list?view=azure-devops-rest-5.1
On Azure AD application setup with permission to acess Azure DevOps API with user consent
Im getting token, however Azure DevOps API keeps returning code 203 with sign in html instead of json response. I would appreciate any suggestions
Thanks
Postman request
GET /[some_org]/_apis/projects?api=5.1 HTTP/1.1
Host: dev.azure.com
Authorization: Bearer [something]
User-Agent: PostmanRuntime/7.17.1
Accept: */*
Cache-Control: no-cache
Postman-Token: [something]
Accept-Encoding: gzip, deflate
Cookie: VstsSession=[something]
Referer: https://dev.azure.com/[some_org]/_apis/projects?api=5.1
Connection: keep-alive cache-control: no-cache
Token get details
I managed to replicate your issue using the OAuth 2.0
authentication in Postman.
I started to look little more about the REST API for Azure DevOps
and I found the document:
https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-5.1
Few key parts:
For Azure DevOps Services, instance is dev.azure.com/{organization},
so the pattern looks like this:
VERB https://dev.azure.com/{organization}/_apis[/{area}]/{resource}?api-version={version}
If you wish to provide the personal access token through an HTTP
header, you must first convert it to a Base64 string (the following
example shows how to convert to Base64 using C#). (Certain tools like
Postman applies a Base64 encoding by default. If you are trying the
API via such tools, Base64 encoding of the PAT is not required).
Authorization: Basic BASE64PATSTRING
I configured my postman to use GET Request and Basic Authentication (and it worked)
GET http://dev.azure.com/{organization-id}/_apis/projects?api-version=5.1
More information about Personal Access Token for Azure DevOps REST API is available
here
PS
And here is page regarding Azure DevOps REST API and OAuth 2.0 Authentication
here
There is information on how to register your application to generate OAuth 2.0 credentials required to authorize.
i am getting this error while requesting for a new token from a refresh token in graph API.
can any i suggest please.
Thanks
It seems like you are forgetting to pass the grant_type, which tells the token service what it should be doing.
You should pass: grant_type=refresh_token
This information can be found in our documentation: Refreshing the access tokens
// Line breaks for legibility only
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=refresh_token
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
We are building a smart home app using actions on google for the google home. Our app requires signing into our system to be able to access the users devices so they can control them using their voice over google home. Our user backend is built using AWS Cognito. We are using API.AI as part of the Google Home app.
I have configured the Cognito OAUTH2 endpoint and the actions on google app to work with each other using the auth code flow and varying scope's but there is something I am missing. When I attempt to link the user account to the Google Home app i get redirected to our login page. After filling out the user details I'm returned to the Google Home 'Discover' tab but there is a message across the bottom that states: ‘Bad response from IdP in Auth Code Exchange’.
I also have tried it using Google's OAUTH2 playground. It seems that when using that I am able to get the code from our OATUH server, but when trying to exchange the code for a token i get the following error:
HTTP/1.1 400 Bad Request
Strict-transport-security: max-age=31536000 ; includeSubDomains
X-content-type-options: nosniff
X-application-context: application:prod:8443
Transfer-encoding: chunked
Set-cookie: XSRF-TOKEN=35f58337-76f4-4993-a0c9-93429134ea42; Path=/; Secure; HttpOnly
Expires: 0
Server: Server
Connection: keep-alive
X-amz-request-id: 284d862e-b021-4079-b5f5-3cbce675983c
X-xss-protection: 1; mode=block
Pragma: no-cache
Cache-control: no-cache, no-store, max-age=0, must-revalidate
Date: Wed, 23 Aug 2017 13:51:42 GMT
X-frame-options: DENY
Content-type: application/json;charset=UTF-8
{
"error": "invalid_client"
}
I have checked and rechecked the client ID and client secret etc and cannot find any errors.
Does anyone have any idea how I might fix this problem?
Thanks in advance
ok,may be i know the reason.....If you use aws cognito ...
According to this doc (http://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html)
Authorization
If the client was issued a secret, the client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization. The secret is Basic Base64Encode(client_id:client_secret).
they need put client and client sectet in header ...
Then I use aws http proxy caught the request of google progress .
Method request headers: {X-Cloud-Trace-Context=d7b6b9b8239965baf69acab659e80a01/13879251242019662389, CloudFront-Viewer-Country=US, CloudFront-Forwarded-Proto=https, CloudFront-Is-Tablet-Viewer=false, CloudFront-Is-Mobile-Viewer=false, User-Agent=google-oauth-playground AppEngine-Google; (+http://code.google.com/appengine; appid: s~oauth2playground), X-Forwarded-Proto=https, CloudFront-Is-SmartTV-Viewer=false, Host=en75z5h2rb.execute-api.us-east-1.amazonaws.com, Accept-Encoding=gzip, deflate, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5a0fcef2-09197cd86a625ad47d78f0b7, Via=1.1 d63a8908759a2f4775b3f672ebf823cc.cloudfront.net (CloudFront), X-Amz-Cf-Id=nFdLK97vAS5HvmpNYkPpbUMOB4bCaM6pScHWTAReAnonLg1gXF7hSg==, X-Forwarded-For=107.178.195.199, 54.182.238.53, content-type=application/x-www-form-urlencoded, CloudFront-Is-Desktop-Viewer=true}
There are no Authorization in request header. So the Cognito will return back
"error": "invalid_client"
According this OAUTH2.0 spec (https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1)
I have already ask AWS support. They said:
Thanks for contacting AWS Support and providing us with detailed references. I would be happy to assist with your question regarding Cognito supporting client credentials in the request-body.
After reading through the OAUTH2.0 Standards RFC 6749 [0], It looks like including the client credentials in the request-body is not recommended. Here's an excerpt on the spec:
"Including the client credentials in the request-body using the two parameters is not recommended and should be limited to clients unable to directly utilize the HTTP Basic authentication scheme (or other password-based HTTP authentication schemes)."
Supposed that the OpenID Connect implicit flow is mainly used by single-page applications (SPA), probably the first access to the backend/API is done by using an AJAX call, not by loading the SPA itself.
Now, if the API detects that the request is being sent without a token, how should it respond?
IMHO it does not make too much sense to respond with a redirect, because this would only cause the AJAX request to be redirected, not the entire browser window (which is necessary).
So, is responding with a 401 fine? Or is there another (better) way of what to do? Supposed that a 401 is fine, should the server somehow indicate which identity provider to use, or is this completely up to the client, and the backend assumes the client to know which identity provider it trusts?
The RFC6749 does not indicate how the response should be designed.
However, as the client expects an API response, your resource server should send an API response with appropriate HTTP code and response body.
If the resource server rejects the request because the token epired or is invalid, the response code should be 400.
If the access token has not been issued with the reauired scope or if the resource owner has no right regarding the resource, then the code should be 403.
If no token is found, the code should be 401.
The body may be similar to the error responses described in the specification:
HTTP/1.1 403 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"error":"insufficient_scope",
"error_description":"The scope 'WRITE' is required.",
"error_uri":"https%3A%2F%2Fwww.example.com%2Fdoc%2Ferror403%2Finsufficient_scope"
}
Concerning the way to indicate which IdP to use, I know that a specification is being written, but at the moment it is up to you to indicate how clients should interact with your resource server (e.g. documentation).
We are trying to implement Google's OAuth 2.0 cross-client sign-on functionality so that our server keeps the tokens and associates them with users, as shown in the diagram for the flow here: Google OAuth 2.0 Server-Side Flow
I am able to successfully retrieve a one-time access code on the client app. I then send that code to the server via a post to "http://example.com/oauth2callback/code="
It gets to the server just fine. The server then attempts a POST to Google that looks like this:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code={My Code}&
client_id={My Client ID}&
client_secret={My Client Secret}&
redirect_uri="http://example.com/oauth2callback"&
grant_type=authorization_code
However, each time the server is returning "Error: redirect_uri_mismatch."
We have tried everything. We double-checked the redirect_uri matches EXACTLY in the Google console and the client ID and client secret are correct. It still doesn't work. Any ideas?
In the "server-side" flow your redirect_uri should be set to postmessage. Unfortunately that is not clearly documented by Google. See also Google OAuth 2.0 "error" : "redirect_uri_mismatch" and related questions/answers.
We figured this out eventually, but I wanted to post this here so that others can find it. It turns out that you should NOT specify a redirect URI if you are exchanging a one-time access code for an access token via communicating with Google's servers from your own server. Instead, it should look like this:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code={My Code}&
client_id={My Client ID}&
client_secret={My Client Secret}&
redirect_uri=''&
grant_type=authorization_code