An ruby (Sinatra) API sends a header __authorization__ to the front end application (vuejs) that uses axios.
This works fine on desktops. On a URL called /getJWT the response headers contain:
__authorization__: eyJhI1NiJ9.eyJ1c2VyIjoijE2NzYxMzA0NjB9.4bSrsh-E2pX2pXeC89Bec
access-control-expose-headers : __authorization__
(__authorization__ contains a valid jwt).
on iOS, the header doesn't get set. On the same URL, I get :
__authorization__:
access-control-expose-headers : __authorization__
(__authorization__ is empty).
On the API-side, I have :
get '/getjwt' do
# HTTP_COOKIE contains the refresh token and rack session token
# remove useless part of HTTP_COOKIE to get value of refresh token
refresh = request.env['HTTP_COOKIE']
.sub(/__refresh_token__=/, '') # remove key __refresh_token__
.sub(/;[^;]*$/,'') # remove the first semicolon and everything after the semicolon
settings.jwt = getjwt(refresh)
headers '__authorization__' => settings.jwt
json_status 204
end
and in the Vuejs app, I put the jwt that the __authorization__ header is supposed to send in a pinia store like so:
function getJWT() {
const jwt = getData.get('/user/b/getjwt')
jwt
.then((response) => {
setJWT(response.headers['__authorization__'])
})
.catch((err) => { alert(err) })
return jwt
}
function setJWT(jowt) {
jwt.value = jowt
}
In this code, getDatais an Axios configuration:
const getData = axios.create({
baseURL: import.meta.env.VITE_API_ROOT,
withCredentials: true,
method: 'get',
headers: {
'Content-Type': 'application/json',
},
})
Related
I am trying to implement the token revocation flow for Apple Sign-In in Firebase, following the instructions given in this GitHub repository: https://github.com/jooyoungho/apple-token-revoke-in-firebase. However, when I try to run the code to get the Refresh Token, I keep receiving a 400 error code from the Axios request.
Here's the code I'm trying to implement:
exports.getRefreshToken = functions.https.onRequest(async (request, response) => {
const axios = require('axios');
const qs = require('qs')
const code = request.query.code;
const client_secret = makeJWT();
let data = {
'code': code,
'client_id': clientId,
'client_secret': client_secret,
'grant_type': 'authorization_code'
}
return axios.post(`https://appleid.apple.com/auth/token`, qs.stringify(data), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
})
.then(async res => {
const refresh_token = res.data.refresh_token;
response.send(refresh_token);
})
.catch((error) => {
response.send(error);
functions.logger.log('Error getting refresh token', {error})
})
});
I am using the app bundleID for client_id
The authorizationCode in my app is formatted in this manner
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.x.xxxxx.xxxxxxxxxxxxxxxxxxxxxx
I am using #awesome-cordova-plugins/sign-in-with-apple to re auth the user right before getting the refresh token so the authCode should still be valid.
I figured out my main issue. I renamed the AuthKey_XXXX.p8 file do not do that. I have the cloud function working locally.
I am working on paypal recurring payment and i need token to get subscriber information to allow it login. But i got unauthorized error. Here is my code
getTokan():Observable<any>{
let client_id = '411820721167-jcuj1jeae0l1j06i3q2otsnol2phlqem.apps.googleusercontent.com';
let secret = 'pe7berpzDSlwDVpgj-NQvseP';
let key = client_id+':'+secret;
let headers = new HttpHeaders({
"Accept": "application/json",
"Accept-Language": "en_US",
'Authorization': 'Basic '+key,
'Content-Type': 'application/x-www-form-urlencoded',
});
let options = { headers: headers };
return this.http.post<any>('https://api.sandbox.paypal.com/v1/oauth2/token',"grant_type=client_credentials", { headers: headers })
}
Explain me what is client id and secret. I am using sandbox client Id secret. i got this error.
zone-evergreen.js:2845 POST https://api.sandbox.paypal.com/v1/oauth2/token 401 (Unauthorized)
That is not a PayPal REST APP's clientId and secret. Get a pair for from the sandbox tab of https://www.paypal.com/signin?intent=developer&returnUri=https%3A%2F%2Fdeveloper.paypal.com%2Fdeveloper%2Fapplications
Also, they must be Base64 encoded in your request
I would like to setup the follownig workflow:
Initially, without login, Swagger shows only 2-3 endpoints - this will be done by providing limited openapi3 json from backend, no problem;
User logs in via Authorize button (works, openapi3 json has necessary info);
After login, Swagger emits one more request with user credentials, backend provides new openapi3 json with endpoints available to this specific user and Swagger redraws the page with new data. Preferably, user is still logged in.
Is it possible to do Item 3 with Swagger? How can I manually emit request from Swagger with OAuth2 bearer token (since user logged, token must present somwhere) and redraw Swagger page?
The task was done via Swagger customization using its plugin system.
Actually Swagger is a JavaScript (Babel, Webpack) project using React / Redux and it was a little bit hard to dig into it since I do not know React (my tool is Python) but finally I managed.
Here is the code for my custom plugin with comments:
const AuthorizedPlugin = function(system) {
return {
statePlugins: {
auth: { // namespace for authentication subsystem
// last components invoked after authorization or logout are
// so-called reducers, exactly they are responsible for page redraw
reducers: {
"authorize_oauth2": function(state, action) {
let { auth, token } = action.payload
let parsedAuth
auth.token = Object.assign({}, token)
parsedAuth = system.Im.fromJS(auth)
var req = {
credentials: 'same-origin',
headers: {
accept: "application/json",
Authorization: "Bearer " + auth.token.access_token
},
method: 'GET',
url: system.specSelectors.url()
}
// this is the additional request with token I mentioned in the question
system.fn.fetch(req).then(
function (result) {
// ... and we just call updateSpec with new openapi json
system.specActions.updateSpec(result.text)
}
)
// This line is from the original Swagger-ui code
return state.setIn( [ "authorized", parsedAuth.get("name") ], parsedAuth )
},
"logout": function(state, action) {
var req = {
credentials: 'same-origin',
headers: { accept: "application/json" },
method: 'GET',
url: system.specSelectors.url()
}
// for logout, request does not contain authorization token
system.fn.fetch(req).then(
function (result) {
system.specActions.updateSpec(result.text)
}
)
// these lines are to make lock symbols gray and remove credentials
var result = state.get("authorized").withMutations(function (authorized) {
action.payload.forEach(function (auth) {
authorized.delete(auth);
});
});
return state.set("authorized", result)
}
}
}
}
}
}
Insert this plugin as usual:
const ui = SwaggerUIBundle({{
url: '{openapi_url}',
dom_id: '#swagger-ui',
defaultModelsExpandDepth: -1,
displayOperationId: false,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
plugins: [
AuthorizedPlugin
],
layout: "BaseLayout",
deepLinking: true
})
I try to search items from eBay API. Within the server.js file at my Apollo Server 2, I pass the token string by context property while instantiation (s. Doku: Apollo context argument). So every request contains the authentication HTTP header property. As a tryout, for now, I just use the fixed token string. This will be changed later if I work for the client.
server.js
import { ApolloServer } from 'apollo-server'
import schema from './schema'
const server = new ApolloServer({
schema,
context: ({ req }) => {
const token = 'Bearer v^1.1#i^1#I^3#f^0#p^1#r^0#t^H4sIAAA...' // my token
return {
...req,
headers: {
...req.headers,
// enrich the header with oauth token
authorization: token,
},
}
},
})
server.listen().then(({ url }) => console.log(`🚀 Server ready at ${url}`))
resolver method
// A map of functions which return data for the schema.
const resolvers = {
Query: {
books(root, { keyword = '' }, context) {
console.log(context.headers)
fetch(`https://api.ebay.com/buy/browse/v1/item_summary/?q=${keyword}`)
.then(response => response.json())
.then(json => console.log(json))
return []
}
}
}
The context.header contains the authorization property:
{ host: 'localhost:4000',
connection: 'keep-alive',
'content-length': '108',
accept: '*/*',
origin: 'http://localhost:4000',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
dnt: '1',
'content-type': 'application/json',
referer: 'http://localhost:4000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'de,en;q=0.9',
authorization: 'Bearer v^1.1#i^1#f^0#p^1#r^0#I^3#t^H4sIAAAAAAAAAOV...'
}
The JSON response contains the error with errorId 1002. It says Access token is missing in the Authorization HTTP request header.:
{ errors:
[ { errorId: 1002,
domain: 'OAuth',
category: 'REQUEST',
message: 'Missing access token',
longMessage: 'Access token is missing in the Authorization HTTP request header.' } ] }
Additionally, I use a new browser tab, enter the URL https://api.ebay.com/buy/browse/v1/item_summary/search?q=test and add the same authorization header property (I use the ModHeader chrome extension). I hit enter, the request works and I get the expected JSON.
It is confusing and I don't know what I'm doing wrong while passing the token. Does somebody have an idea?
The headers you see are the ones being sent in the request to your GraphQL server. All you've done is modified them to include the Authorization header and then included your entire request object as your context -- you're not passing any header information to the fetch call actually getting the data from eBay. Minimally, you want to do something like this:
fetch(`https://api.ebay.com/buy/browse/v1/item_summary/?q=${keyword}`, {
headers: {
Authorization: context.headers.authorization,
},
})
Also bear in mind that the fetch call should be returned inside your resolver, otherwise it won't be awaited.
I am using rails api with puma as an application server and React js as frontend with nginx server as web server. The problem is while I make an api request, for couple of times the server responds with data in json format.
But, after certain request, the web server responds with status 200 ok with no data.When I try to access my data as response.data, I get response.data=""
Request Headers
Response Header
Api request
function fetchHolidays(year) {
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'access-token': Cookie.get('accesstoken'),
'client': Cookie.get('client'),
'uid': Cookie.get('uid'),
'expiry': Cookie.get('expiry'),
'token-type': Cookie.get('tokentype')
}
}
return axios(`${baseURL.URL}${baseURL.PORT}/api/v1/holidays`,
requestOptions).then(response => {
return response
});
}